using System;
using System.Collections.Generic;
using System.Text;
using MacomberMap.Common.User_Interfaces.One_Lines;
using System.IO;
using MacomberMap.Common.Database_Interface.CIM.Components;
using MacomberMap.Common.Components;
using MacomberMap.Common.User_Interfaces.One_Lines.Elements;
using System.Drawing;
using System.Drawing.Drawing2D;
using MacomberMap.Common.Internals;
using MacomberMap.Common.User_Interfaces.Components;
using MacomberMap.Common.Types;
using System.Xml;

namespace MacomberMap.Common.Database_Interface.CIM.One_Line_Interface
{
    /// <summary>
    /// This class is responsible for saving a one-line
    /// </summary>
    public static class MM_DDL_Exporter
    {
        /// <summary>
        /// Save a DDL library
        /// </summary>
        /// <param name="RGB">The path to the RGB file</param>
        /// <param name="olView">The one-line viewer</param>
        /// <param name="Filename">The outgoing filename</param>
        /// <param name="SubElement">The substation element</param>
        /// <param name="Offset">The offset point (based on the position of the scroll window</param>
        /// <param name="ESet">The element set</param>
        public static void SaveDDL(String RGB, MM_OneLine_Viewer olView, string Filename, CIM_Element SubElement, Point Offset, XmlDocument ESet)
        {
            Offset.X += 180;
            MM_Substation BaseSub = olView.BaseElement as MM_Substation;
            MM_DDL_Exporter_Stream DDL = new MM_DDL_Exporter_Stream(Filename);
            MM_DDL_Exporter_Stream DDL2 = new MM_DDL_Exporter_Stream(Filename.Replace("_dset.ddl", "_eset.ddl"));

            foreach (MM_DDL_Exporter_Stream DDLExp in new MM_DDL_Exporter_Stream[] { DDL, DDL2 })
            {
                DDLExp.WriteLine();
                DDLExp.WriteAttribute("version", "WebFG 3.5.0, Builder 5.6.0");
                DDLExp.Indentation++;
                DDLExp.WriteLine();
            }

            //Write our CAMs
            DDL2.WriteStartTag("cam", "LINE_PRIMARY");
            DDL2.WriteAttribute("database", "NETMOM");
            DDL2.WriteAttribute("record", "LN2");
            DDL2.WriteAttribute("gab ( visible )");
            DDL2.WriteAttribute("if proxy(\"%KEY505%\") eq 0");
            DDL2.WriteAttribute("gab ( visible )");
            DDL2.WriteAttribute("else");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteEndTag();

            DDL2.WriteStartTag("cam", "LINE_OTHER");
            DDL2.WriteAttribute("database", "NETMOM");
            DDL2.WriteAttribute("record", "LN2");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteAttribute("if proxy(\"%KEY505%\") eq 1");
            DDL2.WriteAttribute("gab ( visible )");
            DDL2.WriteAttribute("else");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteEndTag();


            DDL2.WriteStartTag("cam", "LINE_SCADA");
            DDL2.WriteAttribute("database", "SCADAMOM");
            DDL2.WriteAttribute("record", "ANALOG");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteAttribute("if proxy(\"%KEY505%\") eq 2");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("visible");
            DDL2.WriteAttribute("foreground", "gray90");
            DDL2.WriteAttribute("font_family", "Arial");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("else");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteEndTag();

            DDL2.WriteStartTag("cam", "LINE_SCADAOTHER");
            DDL2.WriteAttribute("database", "SCADAMOM");
            DDL2.WriteAttribute("record", "ANALOG");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteAttribute("if proxy(\"%KEY505%\") eq 3");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("visible");
            DDL2.WriteAttribute("foreground", "gray90");
            DDL2.WriteAttribute("font_family", "Arial");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("else");
            DDL2.WriteAttribute("gab ( not visible )");
            DDL2.WriteEndTag();


            //Write out our specific GABs
            DDL2.WriteStartTag("gab", "TEXTCOLOR");
            DDL2.WriteAttribute("foreground", "LightGray");
            DDL2.WriteAttribute("font_family", "Arial");
            DDL2.WriteAttribute("font_size", 12);
            DDL2.WriteEndTag();

            DDL2.WriteStartTag("gab", "SMALLTEXTCOLOR");
            DDL2.WriteAttribute("foreground", "LightGray");
            DDL2.WriteAttribute("font_family", "Arial");
            DDL2.WriteAttribute("font_size", 10);
            DDL2.WriteEndTag();

            DDL2.WriteStartTag("gab", "HYPERLINK");
            DDL2.WriteAttribute("foreground", "LightColdBlue");
            DDL2.WriteAttribute("font_family", "Arial");
            DDL2.WriteAttribute("font_underline");
            DDL2.WriteAttribute("font_size", 12);
            DDL2.WriteEndTag();

            DDL2.WriteStartTag("picture", "VIEW_BUTTON");
            DDL2.WriteAttribute("database", "NETMOM");
            DDL2.WriteAttribute("record", "ST");
            DDL2.WriteStartTag("rectangle", "");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "gray90");
            DDL2.WriteAttribute("line_width", 1);
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("origin", 0, 0);
            DDL2.WriteAttribute("width", 123);
            DDL2.WriteAttribute("height", 31);
            DDL2.WriteEndTag();
            DDL2.WriteEndTag();

            //Copy our key pieces of information from the ERCOT ESET




            //Load in our RGB text
            Dictionary<String, Color> FGColors = new Dictionary<string, Color>();
            using (StreamReader sRd = new StreamReader(RGB))
                while (!sRd.EndOfStream)
                {
                    string[] splStr = sRd.ReadLine().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                    FGColors.Add(splStr[3], Color.FromArgb(int.Parse(splStr[0]), int.Parse(splStr[1]), int.Parse(splStr[2])));
                }

            //Write our breaker open/closed state information
            DDL2.WriteStartTag("conditional_text", "BREAKER_STATE_NET");
            DDL2.WriteAttribute("record", "CB");
            DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
            DDL2.WriteAttribute("if field(\"OPEN_CB\") true");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "White");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("text(localize \"O\")");
            DDL2.WriteAttribute("else");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "Black");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("text(localize \"C\")");
            DDL2.WriteEndTag();


            DDL2.WriteStartTag("conditional_text", "BREAKER_STATE_SCADA");
            DDL2.WriteAttribute("record", "point");
            DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
            DDL2.WriteAttribute("if proxy(\"%KEY505%\") lt 2");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("not visible");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("else if field(\"SDIS_POINT\") true");
            DDL2.WriteAttribute("  and field(\"UNACK_POINT\") false");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "Black");
            DDL2.WriteAttribute("visible");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("text(localize \"C\")");
            DDL2.WriteAttribute("else if field(\"UNACK_POINT\") false");
            DDL2.WriteAttribute("   or field(\"SDIS_POINT\") false");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "White");
            DDL2.WriteAttribute("visible");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("text(localize \"O\")");
            DDL2.WriteAttribute("else");
            DDL2.WriteStartTag("gab", "");
            DDL2.WriteAttribute("foreground", "Black");
            DDL2.WriteAttribute("visible");
            DDL2.WriteEndTag();
            DDL2.WriteAttribute("text(localize \"C\")");
            DDL2.WriteEndTag();

            //Write out our line CAMs
            foreach (String str in "NET,SCADA".Split(','))
                foreach (string str2 in "LINE,NODE,TRANSFORMER,TRANSFORMER_DESCRIPTOR,SWITCH,UNIT_GEN,UNIT,BREAKER,LOAD".Split(','))
                    if (str != "NET" || (str2 != "UNIT_GEN" && str2 != "TRANSFORMER_DESCRIPTOR"))
                    {
                        DDL2.WriteStartTag("cam", str + "MOM_" + str2);

                        if (str == "SCADA" && str2 == "UNIT_GEN")
                            DDL2.WriteAttribute("database", "GENMOM");
                        else
                            DDL2.WriteAttribute("database", str + "MOM");

                        if (str == "SCADA" && (str2 == "SWITCH" || str2 == "BREAKER"))
                            DDL2.WriteAttribute("record", "POINT");
                        else if (str == "SCADA" && str2 == "UNIT_GEN")
                            DDL2.WriteAttribute("record", "UNIT");                     
                        else if (str == "SCADA")
                            DDL2.WriteAttribute("record", "ANALOG");
                        else if (str2 == "LINE")
                            DDL2.WriteAttribute("record", "LNLIM");
                        else if (str2 == "NODE")
                            DDL2.WriteAttribute("record", "ND");
                        else if (str2 == "SWITCH" || str2 == "BREAKER")
                            DDL2.WriteAttribute("record", "CB");
                        else if (str2 == "UNIT")
                            DDL2.WriteAttribute("record", "UN");
                        else if (str2 == "LOAD")
                            DDL2.WriteAttribute("record", "LD");
                        else
                            DDL2.WriteAttribute("record", "XF2");

                        DDL2.WriteAttribute("gab (visible)");
                        if (str == "NET")
                            DDL2.WriteAttribute("if proxy(\"%KEY505%\") lt 2");
                        else
                            DDL2.WriteAttribute("if proxy(\"%KEY505%\") gt 1");
                        DDL2.WriteStartTag("gab", "");
                        DDL2.WriteAttribute("visible");
                        if (str2 == "TRANSFORMER_DESCRIPTOR" || str2 == "UNIT")
                            DDL2.WriteAttribute("foreground", "White");
                        DDL2.WriteEndTag();
                        DDL2.WriteAttribute("else");
                        DDL2.WriteAttribute("gab (not visible)");
                        DDL2.WriteEndTag();
                    }

            //Write out our CAMs for switches
            foreach (String str in "NET,SCADA".Split(','))
                foreach (String str2 in "OPEN,CLOSED".Split(','))
                {
                    DDL2.WriteStartTag("cam", str + "MOM_SWITCH_" + str2);
                    if (str == "SCADA")
                        DDL2.WriteAttribute("application", "SCADA");
                    DDL2.WriteAttribute("database", str + "MOM");
                    DDL2.WriteAttribute("record", str == "NET" ? "CB" : "POINT");
                    DDL2.WriteAttribute("gab (visible)");
                    DDL2.WriteAttribute("if proxy(\"%KEY505%\") " + (str == "NET" ? "gt 1" : "lt 2"));
                    DDL2.WriteAttribute("  gab (not visible)");
                    DDL2.WriteAttribute("else if field(\"" + (str == "NET" ? "OPEN_CB" : "SDIS_POINT") + "\") " + (str2 == "OPEN" ^ str == "SCADA" ? "false" : "true"));
                    DDL2.WriteAttribute("  gab (not visible)");
                    DDL2.WriteAttribute("else");
                    DDL2.WriteAttribute("gab (visible)");
                    DDL2.WriteEndTag();
                }

            
            /*//Import our analogs for SCADA
            foreach (String orientation in "U,D,L,R".Split(','))
            {
                DDL2.WriteStartTag("picture", "ANALOG_" + orientation);
                DDL2.WriteAttribute("application", "SCADA");
                DDL2.WriteAttribute("database", "SCADAMOM");
                DDL2.WriteAttribute("record", "ANALOG");
                foreach (XmlElement xElem in ESet.SelectSingleNode("DDL/picture[@Name='ANALOG_" + orientation + "']").ChildNodes)
                {
                    if (xElem.HasAttribute("Name"))
                        DDL2.WriteStartTag(xElem.Name, xElem.Attributes["Name"].Value);
                    else
                        DDL2.WriteStartTag(xElem.Name,"");

                    foreach (XmlAttribute xAttr in xElem.Attributes)
                        if (xAttr.Name != "keyset" && xAttr.Name != "menu" && xAttr.Name != "gab" && xAttr.Name != "cam" && xAttr.Name != "Name")
                            if (xAttr.Value == "true")
                                DDL2.WriteAttribute(xAttr.Name);
                            else        
                                DDL2.WriteAttribute(xAttr.Name, xAttr.Value);
                    DDL2.WriteEndTag();
                }

                DDL2.WriteEndTag();
            }*/
            
            //Write out our descriptors for units, loads, and transformers
            foreach (String Orientation in "Up,Down,Left,Right".Split(','))
            foreach (String str in "UNIT,LOAD,TRANSFORMER".Split(','))
            {
                DDL2.WriteStartTag("picture", str + "_DESCRIPTOR_" + Orientation.Substring(0,1).ToUpper());
                DDL2.WriteAttribute("database", "NETMOM");
                String Record = "";                                
                if (str == "UNIT")
                    DDL2.WriteAttribute("record", Record = "UN");
                else if (str == "LOAD")
                    DDL2.WriteAttribute("record", Record = "LD");
                else if (str == "TRANSFORMER")
                    DDL2.WriteAttribute("record", Record = "XF2");
                //Write out our label
                String[] Title = (str == "TRANSFORMER" ? "MVA" : "MW,MVAR").Split(',');
                String[] Keys = (str == "TRANSFORMER" ? "MVA" : "W,R").Split(',');
                for (int a = 0; a < Title.Length; a++)
                {
                    DDL2.WriteStartTag("formatted_field", "");
                    DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL2.WriteAttribute("origin", 0, (a * 16));
                    DDL2.WriteAttribute("show_char", a.ToString());
                    DDL2.WriteAttribute("size", 5);
                    DDL2.WriteAttribute("position", 1);
                    DDL2.WriteAttribute("format(int)");
                    DDL2.WriteAttribute("factor(1.0000000)");
                    DDL2.WriteAttribute("justification(right) sign_textpair");                    
                    DDL2.WriteAttribute("plus_textpair(bitmap(\"" + Orientation.ToLower() + "_arrow\"))");
                    if (Orientation == "Up")                    
                        DDL2.WriteAttribute("minus_textpair(bitmap(\"down_arrow\"))");
                    else if (Orientation == "Down")
                        DDL2.WriteAttribute("minus_textpair(bitmap(\"up_arrow\"))");
                    else if (Orientation == "Left")
                        DDL2.WriteAttribute("minus_textpair(bitmap(\"right_arrow\"))");
                    else if (Orientation == "Right")
                        DDL2.WriteAttribute("minus_textpair(bitmap(\"left_arrow\"))");
                    DDL2.WriteAttribute("refresh_field");
                    DDL2.WriteAttribute("not refresh_indirect");
                    DDL2.WriteAttribute("not enterable");
                    DDL2.WriteAttribute("show");
                    DDL2.WriteAttribute("field", Keys[a] + "_" + Record);
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("text", "");
                    DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL2.WriteAttribute("origin", 51, (a * 16));
                    DDL2.WriteAttribute("localize \"" + Title[a] + "\"");
                    DDL2.WriteEndTag();
                }
                DDL2.WriteEndTag();
            }

            //Write out our KV level information            
            foreach (MM_KVLevel KVLevel in MM_Overall_Display.KVLevels.Values)
            {
                //Write out our pricing vectors
                foreach (String orientation in "U,D,L,R".Split(','))
                {
                    bool Vertical = orientation == "U" || orientation == "D";
                    DDL2.WriteStartTag("symbol", "PRICING_VECTOR_" + KVLevel.Name.ToUpper().Replace(' ', '_') + "_" + orientation);

                    DDL2.WriteStartTag("rectangle", "");
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("foreground", "Black");
                    DDL2.WriteAttribute("fill");
                    DDL2.WriteEndTag();
                    DDL2.WriteAttribute("origin", 0, 0);
                    DDL2.WriteAttribute("width", Vertical ? 15 : 30);
                    DDL2.WriteAttribute("height", Vertical ? 30 : 15);
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("rectangle", "");
                    DDL2.WriteAttribute("gab (foreground(\"" + ClosestColor(KVLevel.Energized.ForeColor, FGColors) + "\"))");
                    DDL2.WriteAttribute("origin", 0, 0);
                    DDL2.WriteAttribute("width", Vertical ? 15 : 30);
                    DDL2.WriteAttribute("height", Vertical ? 30 : 15);
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("polyline", "");
                    DDL2.WriteAttribute("gab (foreground(\"" + ClosestColor(KVLevel.Energized.ForeColor, FGColors) + "\"))");
                    DDL2.WriteAttribute("origin", Vertical ? 7 : 3, Vertical ? 3 : 7);
                    DDL2.WriteAttribute("point", Vertical ? 7 : 3, Vertical ? 3 : 7);
                    DDL2.WriteAttribute("point", Vertical ? 0 : 23, Vertical ? 23 : 0);
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("polygon", "");
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("fill");
                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                    DDL2.WriteEndTag();
                    int[] TrianglePoints = (orientation == "L" || orientation == "U" ? new int[] { 2, 2, 2, 7, 5, -5, 0, 10, -5, -5 } : new int[] { 23, 2, 28, 7, -5, -5, 0, 10, 5, -5 });
                    for (int a = 0; a < TrianglePoints.Length; a += 2)
                        if (Vertical)
                            DDL2.WriteAttribute(a == 0 ? "origin" : "point", TrianglePoints[a + 1], TrianglePoints[a]);
                        else
                            DDL2.WriteAttribute(a == 0 ? "origin" : "point", TrianglePoints[a], TrianglePoints[a + 1]);
                    DDL2.WriteEndTag();
                    DDL2.WriteEndTag();

                }

                //Write out our transformers and units
                foreach (String ElemType in "TRANSFORMER,UNIT,LOAD".Split(','))
                    foreach (String str in "NET,SCADA".Split(','))
                        foreach (String orientation in (ElemType == "Transformer" ? "U,D,L,R,PHASE" : "U,D,L,R").Split(','))
                        {
                            DDL2.WriteStartTag("picture", ElemType + "_" + KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + str + "_" + orientation);                            
                            if (str == "SCADA" && ElemType == "UNIT")
                                DDL2.WriteAttribute("application", "RTGEN");
                            else if (str == "SCADA")
                                DDL2.WriteAttribute("application", "SCADA");

                            if (str == "SCADA" && ElemType == "UNIT")
                                DDL2.WriteAttribute("database", "GENMOM");
                            else
                                DDL2.WriteAttribute("database", str + "MOM");

                            if (str == "SCADA" && (ElemType == "TRANSFORMER" || ElemType == "LOAD"))
                                DDL2.WriteAttribute("record", "ANALOG");
                            else if (str == "SCADA" && ElemType == "UNIT")
                                DDL2.WriteAttribute("record", "UNIT");
                            else if (ElemType == "TRANSFORMER")
                                DDL2.WriteAttribute("record", "XF2");
                            else if (ElemType == "UNIT")
                                DDL2.WriteAttribute("record", "UN");
                            else if (ElemType == "LOAD")
                                DDL2.WriteAttribute("record", "LD");
                            if (orientation != "PHASE")
                                foreach (XmlElement xElem in ESet.SelectSingleNode("DDL/" + (ElemType == "UNIT" ? "picture" : "symbol") + "[@Name='" + (ElemType == "UNIT" ? (str == "SCADA" ? "GEN" : "GEN_NET") : (ElemType == "LOAD" ? "LOAD" : "TRANS")) + "_138KV_" + orientation + "']").ChildNodes)
                                {

                                    DDL2.WriteStartTag(xElem.Name, "");

                                    //If we have a scale factor, draw it here
                                    XmlElement Scale = xElem["scale_factor"];
                                    if (Scale != null)
                                    {
                                        DDL2.WriteStartTag("scale_factor", "");

                                        //Write our directions
                                        StringBuilder sBd = new StringBuilder();
                                        foreach (XmlAttribute xAttr in Scale["growth"].Attributes)
                                            sBd.Append((sBd.Length == 0 ? "growth(" : " ") + xAttr.Name);
                                        DDL2.WriteAttribute(sBd.ToString() + ")");

                                        //Add in our values
                                        foreach (XmlAttribute xAttr in Scale.Attributes)
                                            if (xAttr.Name.EndsWith("multiplier"))
                                                DDL2.WriteAttribute(xAttr.Name + "(" + xAttr.Value + ")");
                                            else if (xAttr.Name.EndsWith("_bound"))
                                                DDL2.WriteAttribute(xAttr.Name + "(field(\"" + xAttr.Value + "\"))");
                                            else if (xAttr.Value == "true")
                                                DDL2.WriteAttribute(xAttr.Name);
                                            else
                                                DDL2.WriteAttribute(xAttr.Name, xAttr.Value);

                                        DDL2.WriteEndTag();
                                    }

                                    DDL2.WriteStartTag("gab", "");
                                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                                    if (xElem.Attributes["gab"].Value.Contains("FILL") && !xElem.Attributes["gab"].Value.Contains("UNFILL"))
                                        DDL2.WriteAttribute("fill");
                                    DDL2.WriteEndTag();
                                    DDL2.WriteAttribute("origin", int.Parse(xElem.Attributes["origin"].Value.Split(',')[0]), int.Parse(xElem.Attributes["origin"].Value.Split(',')[1]));

                                    if (xElem.HasAttribute("point"))
                                    {
                                        String[] splStr = xElem.Attributes["point"].Value.Split(',');
                                        for (int a = 0; a < splStr.Length; a += 2)
                                            DDL2.WriteAttribute("point", int.Parse(splStr[a]), int.Parse(splStr[a + 1]));
                                    }

                                    foreach (String attr in "width,height,anchor,extent".Split(','))
                                        if (xElem.HasAttribute(attr))
                                            DDL2.WriteAttribute(attr, XmlConvert.ToSingle(xElem.Attributes[attr].Value));



                                    DDL2.WriteEndTag();
                                }
                            if (orientation == "PHASE")
                            {
                                DDL2.WriteStartTag("circle", "");
                                DDL2.WriteAttribute("gab (foreground(\"" + ClosestColor(KVLevel.Energized.ForeColor, FGColors) + "\"))");
                                DDL2.WriteAttribute("origin", 4, 4);
                                DDL2.WriteAttribute("diameter", 12);
                                DDL2.WriteEndTag();

                                DDL2.WriteStartTag("polyline", "");
                                DDL2.WriteAttribute("gab (foreground(\"" + ClosestColor(KVLevel.Energized.ForeColor, FGColors) + "\"))");
                                DDL2.WriteAttribute("origin", 2, 3);
                                DDL2.WriteAttribute("point", 2, 18);
                                DDL2.WriteAttribute("point", 15, -15);
                                DDL2.WriteEndTag();

                                DDL2.WriteStartTag("polygon", "");
                                DDL2.WriteStartTag("gab", "");
                                DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                                DDL2.WriteAttribute("fill");
                                DDL2.WriteEndTag();
                                DDL2.WriteAttribute("origin", 14, 1);
                                DDL2.WriteAttribute("point", 19, 1);
                                DDL2.WriteAttribute("point", -5, 0);
                                DDL2.WriteAttribute("point", 5, 5);
                                DDL2.WriteEndTag();
                            }
                            DDL2.WriteEndTag();

                        }

                //Write out our switch and information
                foreach (String str in "NET,SCADA".Split(','))
                    foreach (string orientation in "V,H".Split(','))
                    {
                        DDL2.WriteStartTag("picture", "SWITCH_" + KVLevel.Name.Replace(' ', '_') + "_" + str + "_" + orientation);
                        if (str == "SCADA")
                            DDL2.WriteAttribute("application", "SCADA");
                        DDL2.WriteAttribute("database", str + "MOM");
                        DDL2.WriteAttribute("record", str == "NET" ? "CB" : "POINT");

                        foreach (XmlElement xElem in ESet.SelectSingleNode("DDL/picture[@Name='SW_138KV_" + orientation + "']").ChildNodes)
                        {

                            DDL2.WriteStartTag(xElem.Name, "");
                            DDL2.WriteStartTag("gab", "");
                            DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                            //DDL2.WriteAttribute("line_width", 2);
                            DDL2.WriteEndTag();
                            DDL2.WriteAttribute("cam \"" + str + "MOM_SWITCH_" + (xElem.Attributes["cam"].Value.Contains("OPEN") ? "OPEN\"" : "CLOSED\""));
                            DDL2.WriteAttribute("origin", int.Parse(xElem.Attributes["origin"].Value.Split(',')[0]), int.Parse(xElem.Attributes["origin"].Value.Split(',')[1]));
                            String[] splStr = xElem.Attributes["point"].Value.Split(',');
                            for (int a = 0; a < splStr.Length; a += 2)
                                DDL2.WriteAttribute("point", int.Parse(splStr[a]), int.Parse(splStr[a + 1]));
                            DDL2.WriteEndTag();
                        }
                        DDL2.WriteEndTag();

                    }

                //Write our breaker and information
                foreach (string str in "NET,SCADA".Split(','))
                {
                    DDL2.WriteStartTag("picture", "BREAKER_" + KVLevel.Name.Replace(' ', '_') + "_" + str);
                    if (str == "SCADA")
                        DDL2.WriteAttribute("application", "SCADA");
                    DDL2.WriteAttribute("database", str + "MOM");
                    DDL2.WriteAttribute("record", str == "NET" ? "CB" : "POINT");

                    DDL2.WriteStartTag("rectangle", "");
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                    DDL2.WriteAttribute("line_width", 2);
                    DDL2.WriteEndTag();

                    DDL2.WriteAttribute("cam \"" + str + "MOM_CB_" + KVLevel.Name.Replace(' ', '_').ToUpper() + "\"");
                    DDL2.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL2.WriteAttribute("origin", 2, 2);
                    DDL2.WriteAttribute("width", 21);
                    DDL2.WriteAttribute("height", 21);
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("conditional_text", "BREAKER_STATE_" + str);
                    DDL2.WriteAttribute("origin", 8, 6);
                    DDL2.WriteEndTag();
                    DDL2.WriteEndTag();
                }


                //Write our line information
                foreach (String str in "NET,SCADA".Split(','))
                    foreach (string Orientation in "U,D,L,R".Split(','))
                    {
                        DDL2.WriteStartTag("picture", "LINE_" + str + "_" + KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + Orientation);
                        if (str == "SCADA")
                            DDL2.WriteAttribute("application", "SCADA");
                        DDL2.WriteAttribute("database", str + "MOM");
                        DDL2.WriteAttribute("record", str == "NET" ? "LNLIM" : "ANALOG");
                        foreach (XmlElement xPoly in ESet.SelectSingleNode("DDL/symbol[@Name='LINE_138KV_" + Orientation + "']").ChildNodes)
                        {
                            DDL2.WriteStartTag(xPoly.Name, "");
                            DDL2.WriteStartTag("gab", "");
                            if (xPoly.Name == "polygon")
                                DDL2.WriteAttribute("fill");
                            DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                            DDL2.WriteEndTag();
                            DDL2.WriteAttribute("origin", int.Parse(xPoly.Attributes["origin"].Value.Split(',')[0]), int.Parse(xPoly.Attributes["origin"].Value.Split(',')[1]));
                            string[] splStr = xPoly.Attributes["point"].Value.Split(',');
                            for (int a = 0; a < splStr.Length; a += 2)
                                DDL2.WriteAttribute("point", int.Parse(splStr[a]), int.Parse(splStr[a + 1]));
                            DDL2.WriteEndTag();
                        }



                        DDL2.WriteEndTag();
                    }


                DDL2.WriteStartTag("gab", KVLevel.Name.Replace(' ', '_').ToUpper());
                DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                DDL2.WriteAttribute("font_family", "Arial");
                DDL2.WriteAttribute("fill");
                DDL2.WriteAttribute("line_width", KVLevel.Energized.Width);
                DDL2.WriteEndTag();



                //Write our breaker CAMS
                DDL2.WriteStartTag("cam", "NETMOM_CB_" + KVLevel.Name.Replace(' ', '_').ToUpper());
                DDL2.WriteAttribute("database", "NETMOM");
                DDL2.WriteAttribute("record", "CB");
                DDL2.WriteAttribute("gab (visible)");
                DDL2.WriteAttribute("if proxy(\"%KEY505%\") gt 1");
                DDL2.WriteAttribute("gab (not visible)");
                DDL2.WriteAttribute("else if field(\"OPEN_CB\") true");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("not fill");
                DDL2.WriteEndTag();
                DDL2.WriteAttribute("else");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("fill");
                DDL2.WriteEndTag();
                DDL2.WriteEndTag();

                DDL2.WriteStartTag("cam", "SCADAMOM_CB_" + KVLevel.Name.Replace(' ', '_').ToUpper());
                DDL2.WriteAttribute("database", "SCADAMOM");
                DDL2.WriteAttribute("record", "POINT");
                DDL2.WriteAttribute("gab (visible)");
                DDL2.WriteAttribute("if proxy(\"%KEY505%\") lt 2");
                DDL2.WriteAttribute("gab (not visible)");
                DDL2.WriteAttribute("else if field(\"SDIS_POINT\") true");
                DDL2.WriteAttribute("  and field(\"UNACK_POINT\") false");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("fill");
                DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                DDL2.WriteEndTag();
                DDL2.WriteAttribute("else if field(\"UNACK_POINT\") false");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("foreground", "Yellow");
                DDL2.WriteAttribute("not fill");
                DDL2.WriteEndTag();
                DDL2.WriteAttribute("else if field(\"SDIS_POINT\") false");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("foreground", "Yellow");
                DDL2.WriteAttribute("not fill");
                DDL2.WriteAttribute("blink");
                DDL2.WriteEndTag();
                DDL2.WriteAttribute("else");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                DDL2.WriteAttribute("fill");
                DDL2.WriteEndTag();
                DDL2.WriteEndTag();
                /*           
                foreach (String str2 in "NET,SCADA".Split(','))                
                    for (int Angle = 0; Angle < 360; Angle += 90)
                    {
                        Char Orientation = "URDL"[Angle / 90];
                        DDL2.WriteStartTag("picture", "LINE_" + KVLevel.Name.Replace(' ', '_') + "_" + Orientation + "_" + str2);
                        if (str2 == "SCADA")
                            DDL2.WriteAttribute("application", "SCADA");
                        DDL2.WriteAttribute("database", str2 + "MOM");
                        DDL2.WriteAttribute(str2 == "SCADA" ? "ANALOG" : "LNLIM");

                        DDL2.WriteStartTag("polygon", "");
                        DDL2.WriteStartTag("gab", "");
                        DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                        DDL2.WriteAttribute("fill");
                        DDL2.WriteEndTag();
                        DDL2.WriteRotatedAttribute("origin", 0, 8, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", 0, 8, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", 12, 0, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", -6, 12, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", -6, -12, 12, 20, Angle);
                        DDL2.WriteEndTag();

                        DDL2.WriteStartTag("polyline", "");
                        DDL2.WriteStartTag("gab", "");
                        DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                        DDL2.WriteEndTag();
                        DDL2.WriteRotatedAttribute("origin", 6, 0, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", 6, 0, 12, 20, Angle);
                        DDL2.WriteRotatedAttribute("point", 0, 8, 12, 20, Angle);
                        DDL2.WriteEndTag();

                        DDL2.WriteEndTag();
                    }
               

            } */
                foreach (String str in "POINT,ANALOG".Split(','))
                {
                    DDL2.WriteStartTag("cam", "SCADAMOM_" + str + "_" + KVLevel.Name.Replace(' ', '_').ToUpper());
                    DDL2.WriteAttribute("database", "SCADAMOM");
                    DDL2.WriteAttribute("database", str);
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("visible");
                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                    DDL2.WriteAttribute("font_family", "Arial");
                    DDL2.WriteEndTag();
                    DDL2.WriteAttribute("if proxy(\"%KEY505%\") lt 2");
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("visible");
                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                    DDL2.WriteAttribute("font_family", "Arial");
                    DDL2.WriteEndTag();
                    DDL2.WriteAttribute("else");
                    DDL2.WriteAttribute("gab (not visible)");
                    DDL2.WriteEndTag();
                }

                //Write out our node points
                foreach (String str in "NET,SCADA".Split(','))
                {
                    DDL2.WriteStartTag("picture", "NODE_" + KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + str);
                    if (str == "SCADA")
                        DDL2.WriteAttribute("application", str);
                    DDL2.WriteAttribute("database", str + "MOM");
                    DDL2.WriteAttribute("record", str == "NET" ? "ND" : "ANALOG");
                    DDL2.WriteStartTag("rectangle", "");
                    DDL2.WriteStartTag("gab", "");
                    DDL2.WriteAttribute("visible");
                    DDL2.WriteAttribute("foreground", ClosestColor(KVLevel.Energized.ForeColor, FGColors));
                    DDL2.WriteAttribute("fill");
                    DDL2.WriteEndTag();
                    DDL2.WriteAttribute("origin", 0, 0);
                    DDL2.WriteAttribute("width", 8);
                    DDL2.WriteAttribute("height", 8);
                    DDL2.WriteEndTag();
                    DDL2.WriteEndTag();
                }
            }

            //Write out our pictures
            String[] Params = "ERCOT_LOGO,ERCOTLogo_Small_Blue.bmp,95,25,MAP_ONELINE_BACKGROUND,OneLineBackground.bmp,180,180,MAP_STATE,TexasMap.bmp,180,180".Split(',');
            for (int a = 0; a < Params.Length; a += 4)
            {
                DDL2.WriteStartTag("symbol", Params[a]);
                DDL2.WriteStartTag("rectangle", "");
                DDL2.WriteAttribute("gab ( )");
                DDL2.WriteAttribute("origin", 0, 0);
                DDL2.WriteAttribute("width", int.Parse(Params[a + 2]));
                DDL2.WriteAttribute("height", int.Parse(Params[a + 3]));
                DDL2.WriteEndTag();
                DDL2.WriteAttribute("image", Params[a + 1]);
                DDL2.WriteAttribute("image_attachment(none)");
                DDL2.WriteEndTag();
            }


            DDL.WriteStartTag("display", "Mike_Test"); //SubElement.Name);

            //Write our title
            DDL.WriteLine();
            DDL.WriteAttribute("title", "localize", "%DIS%,%DISAPP%[%DISFAM%]    %HOST% (%VP%)    %REF%");


            //Write out our applications and high level data
            foreach (String str in "RTNET,SMTNET,STNET,DTSPSM".Split(','))
                DDL.WriteAttribute("application", str);
            DDL.WriteAttribute("color", "Black");
            DDL.WriteAttribute("scale_to_fit_style(XY)");
            DDL.WriteStartTag("menu_bar_item", "ERCOT_DISPLAYS");
            DDL.WriteAttribute("label", "localize", "Onelines");
            DDL.WriteAttribute("set", "ERCOTONELINES");
            DDL.WriteEndTag();
            DDL.WriteAttribute("horizontal_unit", 10);
            DDL.WriteAttribute("vertical_unit", 10);
            DDL.WriteAttribute("horizontal_page", 50);
            DDL.WriteAttribute("vertical_page", 50);
            DDL.WriteAttribute("refresh", 2);
            DDL.WriteAttribute("not locked_in_viewport");
            DDL.WriteAttribute("horizontal_scroll_bar");
            DDL.WriteAttribute("vertical_scroll_bar");
            DDL.WriteAttribute("not std_menu_bar");
            DDL.WriteAttribute("not command_window");
            DDL.WriteAttribute("not on_top");
            DDL.WriteAttribute("not ret_last_tab_pnum");
            DDL.WriteAttribute("default_zoom(1.0000000)");

            //Start our network layer
            DDL.WriteStartTag("simple_layer", "NETWORK");
            DDL.WriteAttribute("driving_app", "SCADA");

            //Write our netapp header
            DDL.WriteStartTag("picture", "NETWORK_ONELINE_NETAPP_HEADER");
            DDL.WriteAttribute("set", "ERCOTONELINES");
            DDL.WriteAttribute("origin", 0, 0);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");
            DDL.WriteEndTag();

            //Write our NETMOM header
            DDL.WriteStartTag("picture", "NETWORK_ONELINE_NETMOM_HEADER");
            DDL.WriteAttribute("set", "ERCOTONELINES");
            DDL.WriteAttribute("origin", 0, 0);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "ST");
            DDL.WriteAttribute("record_key", SubElement.Name);
            DDL.WriteEndTag();
            DDL.WriteEndTag();

            //Write our substation name
            DDL.WriteStartTag("text", "");
            DDL.WriteAttribute("gab \"TEXT_FV_CHR_NONENTRY_TITLE_18PNT\"");
            DDL.WriteAttribute("set", "ERCOTONELINES");
            DDL.WriteAttribute("origin", 640, Offset.Y + 5);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");

            //Write our tooltip information for our substation

            DDL.WriteToolTip(BaseSub, "  in county: " + BaseSub.County, "  Latitude: " + BaseSub.Latitude.ToString("0.000"), "  Longitude: " + BaseSub.Longitude.ToString("0.000"));

            if (String.IsNullOrEmpty(BaseSub.LongName) || BaseSub.LongName.Equals(BaseSub.Name, StringComparison.CurrentCultureIgnoreCase))
                DDL.WriteAttribute("localize \"" + BaseSub.Name + "\"");
            else
                DDL.WriteAttribute("localize \"" + BaseSub.LongName + "\"");
            DDL.WriteEndTag();




            //Write out our map
            WriteMap(olView, SubElement, DDL, DDL2);


            //Now, go through each one-line element, and write it out
            foreach (MM_OneLine_Node Node in olView.DisplayNodes.Values)
                WriteNode(Node, BaseSub, DDL, DDL2, Offset);


            //Write our backgrounds behind all display elements
            foreach (MM_OneLine_Element oElem in olView.DisplayElements.Values)
                if (oElem is MM_OneLine_Node == false)
                {
                    //First, write our black background images
                    DDL.WriteStartTag("rectangle", "");
                    DDL.WriteStartTag("gab", "");
                    DDL.WriteAttribute("foreground", "Black");
                    DDL.WriteAttribute("fill");
                    DDL.WriteEndTag();
                    DDL.WriteAttribute("origin", Offset.X + oElem.Left + 3, Offset.Y + oElem.Top + 3);
                    DDL.WriteAttribute("width", oElem.Width - 6);
                    DDL.WriteAttribute("height", oElem.Height - 6);
                    DDL.WriteEndTag();
                }

            //Write out our elements
            foreach (MM_OneLine_Element oElem in olView.DisplayElements.Values)
                if (oElem is MM_OneLine_Breaker)
                    WriteBreaker(oElem as MM_OneLine_Breaker, BaseSub, DDL, DDL2, Offset);
                else if (oElem is MM_OneLine_Line)
                    WriteLine(oElem as MM_OneLine_Line, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Switch)
                    WriteSwitch(oElem as MM_OneLine_Switch, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Unit)
                    WriteUnit(oElem as MM_OneLine_Unit, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Capacitor)
                    WriteCapacitor(oElem as MM_OneLine_Capacitor, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_EndCap)
                    WriteEndCap(oElem as MM_OneLine_EndCap, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_LAAR)
                    WriteLaaR(oElem as MM_OneLine_LAAR, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Load)
                    WriteLoad(oElem as MM_OneLine_Load, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_PricingVector)
                    WritePricingVector(oElem as MM_OneLine_PricingVector, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Reactor)
                    WriteReactor(oElem as MM_OneLine_Reactor, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_StaticVarCompensator)
                    WriteStaticVarCompensator(oElem as MM_OneLine_StaticVarCompensator, BaseSub, DDL, DDL2, olView, Offset);
                else if (oElem is MM_OneLine_Transformer)
                    WriteTransformer(oElem as MM_OneLine_Transformer, BaseSub, DDL, DDL2, olView, Offset);


            //Now, write our telemetry
            foreach (MM_OneLine_Element Elem in olView.DisplayElements.Values)
                if (Elem.Descriptor != null)
                    if (Elem is MM_OneLine_Line)
                        foreach (String Layer in "PRIMARY,OTHER,SCADA,SCADAOTHER".Split(','))
                            WriteLabel(Elem, Layer, BaseSub, DDL, DDL2, olView, Offset);
                    else if (Elem is MM_OneLine_Load || Elem is MM_OneLine_Unit)
                        foreach (String Layer in "NETMOM,SCADA".Split(','))
                            WriteLabel(Elem, Layer, BaseSub, DDL, DDL2, olView, Offset);
                    else
                        WriteLabel(Elem, "", BaseSub, DDL, DDL2, olView, Offset);

            DDL.Close();
            DDL2.Close();
        }

        /// <summary>
        /// Write out the information for an End Cap
        /// </summary>
        /// <param name="EndCap"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteEndCap(MM_OneLine_EndCap EndCap, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        { }

        /// <summary>
        /// Write out the information for a static var compensator
        /// </summary>
        /// <param name="SVC"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteStaticVarCompensator(MM_OneLine_StaticVarCompensator SVC, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {}

        /// <summary>
        /// Write out the information for a capacitor
        /// </summary>
        /// <param name="Capacitor"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteCapacitor(MM_OneLine_Capacitor Capacitor, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        { }

        /// <summary>
        /// Write out the information for a reactor
        /// </summary>
        /// <param name="Reactor"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteReactor(MM_OneLine_Reactor Reactor, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        { }

        /// <summary>
        /// Write out the information for a pricing vector
        /// </summary>
        /// <param name="Vector"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WritePricingVector(MM_OneLine_PricingVector Vector, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        { }

        /// <summary>
        /// Write out the information for a tranformer/phase shifter
        /// </summary>
        /// <param name="Transformer"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteTransformer(MM_OneLine_Transformer Transformer, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {            
            foreach (MM_OneLine_TransformerWinding Winding in Transformer.Windings)
                foreach (String str in "NET,SCADA".Split(','))
            {
                DDL.WriteStartTag("picture", "TRANSFORMER_" + Winding.KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + str + "_" + (Winding.IsPhaseShifter ? "PHASE" : Winding.Orientation.ToString().Substring(0, 1)));
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("cam", str + "MOM_TRANSFORMER");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", Offset.X + Winding.Bounds.Left + Transformer.Left, Offset.Y + Winding.Bounds.Top + Transformer.Top - 1);
                
                if (str == "NET")
                {
                    DDL.WriteToolTip(Winding.BaseElement, "MVA:  %%MVA_XF2%%", "MW:   %%W_XF2%%", "MVAR: %%R_XF2%%", "AMP:  %%AMP_XF2%%", "","Tap (Est): %%I__XF_XF2 TAP_XF%%", "Tap (Min): %%I__XF_XF2 I__TAPTY_XF MN_TAPTY%%", "Tap (Max): %%I__XF_XF2 I__TAPTY_XF MX_TAPTY%%");                        
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "ST");
                    DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
                    DDL.WriteAttribute("record", "ND");
                    foreach (CIM_Element WindingNode in MM_Database_CIM.TEIDs[Winding.BaseElement.TEID].Nodes)
                        if (WindingNode.Type == "cim:ConnectivityNode")
                            DDL.WriteAttribute("record_key", WindingNode.Name.ToUpper());                                            
                    DDL.WriteAttribute("record", "XF2");
                    DDL.WriteAttribute("record_key", Winding.BaseElement.Name.ToUpper());
                }
                else
                {
                    DDL.WriteToolTip(Winding.BaseElement);
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "SUBSTN");                    
                    DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());

                    DDL.WriteAttribute("record", "DEVTYP");
                    DDL.WriteAttribute("record_key", "XF");

                    DDL.WriteAttribute("record", "DEVICE");
                    DDL.WriteAttribute("record_key", Winding.BaseElement.Name.ToUpper());

                    DDL.WriteAttribute("record", "ANALOG");
                    DDL.WriteAttribute("record_key", "MW");
                }
                DDL.WriteEndTag();
                DDL.WriteEndTag();
            }        
        
        }

        /// <summary>
        /// Write out the information for a LaaR
        /// </summary>
        /// <param name="Laar"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteLaaR(MM_OneLine_LAAR Laar, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        { 
        }

        /// <summary>
        /// Write out the information for a load
        /// </summary>
        /// <param name="Load"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>        
        private static void WriteLoad(MM_OneLine_Load Load, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {
            DDL.WriteStartTag("picture", "LOAD_" + Load.KVLevel.Name.Replace(' ', '_').ToUpper() + "_NET_" + Load.Orientation.ToString().Substring(0, 1));
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "NETMOM_LOAD");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", Offset.X + Load.Left + 1, Offset.Y + Load.Top - 1);
            DDL.WriteToolTip(Load.BaseElement, "MW:  %%W_LD%%", "MVAR: %%R_LD%%");
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "ST");
            DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
            DDL.WriteAttribute("record", "LD");
            DDL.WriteAttribute("record_key", Load.BaseElement.Name.ToUpper());
            DDL.WriteEndTag();
            DDL.WriteEndTag();

            DDL.WriteStartTag("picture", "LOAD_" + Load.KVLevel.Name.Replace(' ', '_').ToUpper() + "_SCADA_" + Load.Orientation.ToString().Substring(0, 1));
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "SCADAMOM_LOAD");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", Offset.X + Load.Left + 1, Offset.Y + Load.Top - 1);
            DDL.WriteToolTip(Load.BaseElement);
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "SUBSTN");
            DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
            DDL.WriteAttribute("record", "DEVTYP");
            DDL.WriteAttribute("record_key", "LD");
            DDL.WriteAttribute("record", "DEVICE");
            DDL.WriteAttribute("record_key", Load.BaseElement.Name.ToUpper());
            DDL.WriteAttribute("record", "ANALOG");
            DDL.WriteAttribute("record_key", "MW");
            DDL.WriteEndTag();
            DDL.WriteEndTag();


            //Write the NETMOM label
            if (Load.Descriptor != null)
            {
                DDL2.WriteStartTag("picture", "LOAD_" + Load.BaseElement.Substation.Name.ToUpper() + "_" + Load.BaseElement.Name.ToUpper() + "_DESCRIPTOR");
                DDL2.WriteAttribute("database", "NETMOM");
                DDL2.WriteAttribute("record", "LD");
                DDL2.WriteStartTag("text", "");
                DDL2.WriteAttribute("gab \"TEXTCOLOR\"");                
                DDL2.WriteToolTip(Load.BaseElement);
                DDL2.WriteAttribute("origin", 0, 0);
                DDL2.WriteAttribute("localize \"" + Load.BaseElement.Name + "\"");
                DDL2.WriteEndTag();


                //Write out our label
                String[] Title = "MW,MVAR".Split(',');
                String[] Keys = "W,R".Split(',');
                for (int a = 0; a < 2; a++)
                {
                    DDL2.WriteStartTag("formatted_field", "");
                    DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL2.WriteAttribute("origin", 0, 16 + (a * 16));
                    DDL2.WriteAttribute("show_char", a.ToString());
                    DDL2.WriteAttribute("size", 5);
                    DDL2.WriteAttribute("position", 1);
                    DDL2.WriteAttribute("format(int)");
                    DDL2.WriteAttribute("factor(1.0000000)");
                    DDL2.WriteAttribute("justification(right) sign_textpair");
                    DDL2.WriteAttribute("plus_textpair(bitmap(\"" + Load.Descriptor.Orientation.ToString().ToLower() + "_arrow\"))");
                    DDL2.WriteAttribute("minus_textpair(bitmap(\"" + Load.Descriptor.InvertedOrientation.ToString().ToLower() + "_arrow\"))");
                    DDL2.WriteAttribute("refresh_field");
                    DDL2.WriteAttribute("not refresh_indirect");
                    DDL2.WriteAttribute("not enterable");
                    DDL2.WriteAttribute("show");
                    DDL2.WriteAttribute("field", Keys[a] + "_LD");
                    DDL2.WriteEndTag();

                    DDL2.WriteStartTag("text", "");
                    DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL2.WriteAttribute("origin", 51, 16 + (a * 16));
                    DDL2.WriteAttribute("localize \"" + Title[a] + "\"");
                    DDL2.WriteEndTag();
                }
                DDL2.WriteEndTag();
            }
        }


        /// <summary>
        /// Write out the information for a switch
        /// </summary>
        /// <param name="Switch"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>
        private static void WriteSwitch(MM_OneLine_Switch Switch, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {
           

            DDL.WriteStartTag("picture", "SWITCH_" + Switch.KVLevel.Name.Replace(' ', '_').ToUpper() + "_NET_" + Switch.Orientation.ToString().Substring(0,1));
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "NETMOM_SWITCH");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", Offset.X + Switch.Left + 1, Offset.Y + Switch.Top + 1);
            DDL.WriteToolTip(Switch.BaseElement, "NETMOM opened state: %%OPEN_CB%%");
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "ST");
            DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
            DDL.WriteAttribute("record", "CBTYP");
            DDL.WriteAttribute("record_key", "DSC");
            DDL.WriteAttribute("record", "CB");
            DDL.WriteAttribute("record_key", Switch.BaseElement.Name.ToUpper());
            DDL.WriteEndTag();
            DDL.WriteEndTag();

            DDL.WriteStartTag("picture", "SWITCH_" + Switch.KVLevel.Name.Replace(' ', '_').ToUpper() + "_SCADA_" + Switch.Orientation.ToString().Substring(0, 1));
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "SCADAMOM_SWITCH");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", Offset.X + Switch.Left + 1, Offset.Y + Switch.Top + 1);
            DDL.WriteToolTip(Switch.BaseElement, "SCADA state: %%SDIS_POINT%%", "SCADA unack: %%UNACK_POINT%%");
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "SUBSTN");
            DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
            DDL.WriteAttribute("record", "DEVTYP");
            DDL.WriteAttribute("record_key", "DSC");
            DDL.WriteAttribute("record", "DEVICE");
            DDL.WriteAttribute("record_key", Switch.BaseElement.Name.ToUpper());
            DDL.WriteAttribute("record", "POINT");
            DDL.WriteAttribute("record_key", "ST");
            DDL.WriteEndTag();
            DDL.WriteEndTag();
        }

        /// <summary>
        /// Write out the information for a unit
        /// </summary>
        /// <param name="Unit"></param>
        /// <param name="BaseSub"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>
        private static void WriteUnit(MM_OneLine_Unit Unit, MM_Substation BaseSub, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {
            foreach (String str in "NET,SCADA".Split(','))
            {
                DDL.WriteStartTag("picture", "UNIT_" + Unit.KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + str + "_" + Unit.Orientation.ToString().Substring(0,1));
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", Unit.Left + Offset.X + 1, Unit.Top + Offset.Y);
                DDL.WriteAttribute("cam", str == "SCADA" ? "SCADAMOM_UNIT_GEN" : str + "MOM_UNIT");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());

                if (str == "SCADA")
                {
                    DDL.WriteToolTip(Unit.BaseElement);
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "PL");
                    DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
                    DDL.WriteAttribute("record", "PLC");
                    DDL.WriteAttribute("record_key", Unit.BaseElement.Name.ToUpper());
                    DDL.WriteAttribute("record", "UNIT");
                    DDL.WriteAttribute("record_key", Unit.BaseElement.Name.ToUpper());
                    DDL.WriteEndTag();
                }
                else
                {
                    DDL.WriteToolTip(Unit.BaseElement, "MW:  %%W_UN%%", "MVAR: %%R_UN%%");
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "ST");
                    DDL.WriteAttribute("record_key", BaseSub.Name.ToUpper());
                    DDL.WriteAttribute("record", "UN");
                    DDL.WriteAttribute("record_key", Unit.BaseElement.Name.ToUpper());
                    DDL.WriteEndTag();                    
                }
             
                DDL.WriteEndTag();
            }
        }

        /// <summary>
        /// Write out our map
        /// </summary>
        /// <param name="olView"></param>
        /// <param name="SubElement"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        private static void WriteMap(MM_OneLine_Viewer olView, CIM_Element SubElement, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2)
        {
           
            //First, place our elements
            String[] splStr = "MAP_ONELINE_BACKGROUND,0,34,MAP_STATE,0,214".Split(',');
            for (int a = 0; a < splStr.Length; a += 3)
            {
                DDL.WriteStartTag("symbol", splStr[a]);
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", int.Parse(splStr[a + 1]), int.Parse(splStr[a + 2]));
                DDL.WriteAttribute("xlocked");
                DDL.WriteAttribute("ylocked");
                DDL.WriteEndTag();
            }

            //Now, draw our state crosshairs
            PointF LatLng = (olView.BaseElement as MM_Substation).LatLong;
            MM_Boundary StateBoundary = MM_Repository.StateBoundary;

            Point SubstationPoint = Point.Round(new PointF(180f * (LatLng.X - StateBoundary.Min.X) / (StateBoundary.Max.X - StateBoundary.Min.X), 180f * (LatLng.Y - StateBoundary.Max.Y) / (StateBoundary.Min.Y - StateBoundary.Max.Y)));
            Point MinPoint, MaxPoint;
            MinPoint = MaxPoint = SubstationPoint;
            Dictionary<MM_Line, Point> LinePoints = new Dictionary<MM_Line, Point>();
            

            //Now, draw the regioual view around the substation
            MM_Substation Substation = olView.BaseElement as MM_Substation;

            PointF CenterPoint = new PointF(90, 90);
            float MileDistance = float.NaN;
            List<MM_Line> Lines = new List<MM_Line>();

            //Pull in our lines and determine our mile distance
            foreach (MM_OneLine_Element Elem in olView.DisplayElements.Values)
                if (Elem is MM_OneLine_Line)
                {
                    MM_Line Line = Elem.BaseElement as MM_Line;
                    Lines.Add(Line);
                    if (Line.ConnectedStations[1] != Substation)
                    {
                        float ThisDistance = Line.ConnectedStations[1].DistanceTo(Substation);
                        if (float.IsNaN(MileDistance) || (MileDistance < ThisDistance))
                            MileDistance = ThisDistance;
                    }
                    else if (Line.ConnectedStations[0] != Substation)
                    {
                        float ThisDistance = Line.ConnectedStations[0].DistanceTo(Substation);
                        if (float.IsNaN(MileDistance) || (MileDistance < ThisDistance))
                            MileDistance = ThisDistance;
                    }
                }

            if (!float.IsNaN(MileDistance))
                MileDistance *= 1.2f;

            //Now go through and render all lines in the detailed view
            foreach (MM_Line Line in Lines)
            {
                MM_Substation OtherStation = null;
                if (Line.ConnectedStations[0] != Substation)
                    OtherStation = Line.ConnectedStations[0];
                else if (Line.ConnectedStations[1] != Substation)
                    OtherStation = Line.ConnectedStations[1];
                if (OtherStation != null)
                {
                    float DistanceRatio = CenterPoint.X * Substation.DistanceTo(OtherStation) / MileDistance;
                    Point TargetPoint = Point.Round(new PointF((float)Math.Cos(Substation.AngleTo(OtherStation)) * DistanceRatio + CenterPoint.X, -(float)Math.Sin(Substation.AngleTo(OtherStation)) * DistanceRatio + CenterPoint.Y));
                    DDL.WriteStartTag("polyline", "");
                    DDL.WriteAttribute("gab \"" + Line.KVLevel.Name.Replace(' ', '_').ToUpper() + "\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteToolTip(Line);
                    DDL.WriteAttribute("origin", TargetPoint.X, TargetPoint.Y + 31);
                    DDL.WriteAttribute("xlocked");
                    DDL.WriteAttribute("ylocked");
                    DDL.WriteAttribute("point", TargetPoint.X, TargetPoint.Y + 31);
                    DDL.WriteAttribute("point", CenterPoint.X - TargetPoint.X, CenterPoint.Y - TargetPoint.Y);
                    DDL.WriteEndTag();

                    //Now, also write out our label
                    DDL.WriteStartTag("text", "");
                    DDL.WriteAttribute("gab \"HYPERLINK\"");                    
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    if (String.IsNullOrEmpty(OtherStation.LongName) || OtherStation.LongName == OtherStation.Name)
                        DDL.WriteAttribute("tool_tip(localize \"Navigate to " + OtherStation.Name + "\" )");
                    else
                        DDL.WriteAttribute("tool_tip(localize \"Navigate to " + OtherStation.LongName + " (" + OtherStation.Name + ")\" )");
                    

                    DDL.WriteAttribute("keyset \"" + OtherStation.Name.ToUpper() + "_CALLUP\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());



                    //double Angle = Math.Atan2(TargetPoint.Y - CenterPoint.Y, TargetPoint.X - CenterPoint.X);
                    //double Dist = Math.Sqrt(Math.Pow(TargetPoint.Y - CenterPoint.Y, 2) + Math.Pow(TargetPoint.X - CenterPoint.X, 2)) + 5;
                    //DDL.WriteAttribute("origin", (float)Math.Round(Math.Cos(Angle) * Dist)+CenterPoint.X, (float)Math.Round(Math.Sin(Angle)*Dist)+CenterPoint.Y);                        
                    DDL.WriteAttribute("origin", TargetPoint.X, TargetPoint.Y + 31);
                    DDL.WriteAttribute("xlocked");
                    DDL.WriteAttribute("ylocked");
                    DDL.WriteAttribute("localize \"" + OtherStation.LongName + "\"");
                    DDL.WriteEndTag();

                    //Add our main map point
                    Point OtherPoint = Point.Round(new PointF(180f * (OtherStation.LatLong.X - StateBoundary.Min.X) / (StateBoundary.Max.X - StateBoundary.Min.X), 180f * (OtherStation.LatLong.Y - StateBoundary.Max.Y) / (StateBoundary.Min.Y - StateBoundary.Max.Y)));
                    LinePoints.Add(Line, OtherPoint);
                    MinPoint.X = Math.Min(MinPoint.X, OtherPoint.X);
                    MinPoint.Y = Math.Min(MinPoint.Y, OtherPoint.Y);
                    MaxPoint.X = Math.Max(MaxPoint.X, OtherPoint.X);
                    MaxPoint.Y = Math.Max(MaxPoint.Y, OtherPoint.Y);

                    //Write out our callout keyset
                    DDL2.WriteStartTag("keyset", OtherStation.Name.ToUpper() + "_CALLUP");
                    DDL2.WriteAttribute("key", "SELECT");
                    DDL2.WriteAttribute("command", "DISPLAY /APP=%APP% " + OtherStation.Name.ToUpper());
                    DDL2.WriteEndTag();
                }
            }




            //Now, write our legend                
            DDL.WriteStartTag("polyline", "");
            DDL.WriteAttribute("gab \"TEXTCOLOR\"");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", 2, 38);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");
            DDL.WriteAttribute("point", 3, 47);
            DDL.WriteAttribute("point", 0, -5);
            DDL.WriteAttribute("point", 46, 0);
            DDL.WriteAttribute("point", 0, 5);
            DDL.WriteEndTag();

            DDL.WriteStartTag("text", "");
            DDL.WriteAttribute("gab \"SMALLTEXTCOLOR\"");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", 7, 46);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");
            DDL.WriteAttribute("localize \"" + MileDistance.ToString("0.0") + " mi\"");
            DDL.WriteEndTag();


            //Now write our main map.
            MinPoint.X -= 2;
            MinPoint.Y -= 2;
            MaxPoint.X += 2;
            MaxPoint.Y += 2;

            //Draw our rectangle around our point
            DDL.WriteStartTag("rectangle", "");
            DDL.WriteAttribute("gab \"TEXTCOLOR\"");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());

            DDL.WriteAttribute("origin", MinPoint.X, MinPoint.Y+214);
            DDL.WriteAttribute("xlocked");
            DDL.WriteAttribute("ylocked");
            DDL.WriteAttribute("width", MaxPoint.X - MinPoint.X);
            DDL.WriteAttribute("height", MaxPoint.Y - MinPoint.Y);
            DDL.WriteEndTag();
                

            //Now, draw our cross-hairs            
            Point CenterMap = MM_OneLine_Element.CenterRect(Rectangle.FromLTRB(MinPoint.X, MinPoint.Y, MaxPoint.X, MaxPoint.Y));
            for (int a = 0; a < 4; a++)
            {
                DDL.WriteStartTag("polyline", "");
                DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                Point From, To;
                if (a == 0)
                {
                    
                    From = new Point(0, 214 + SubstationPoint.Y);
                    To = new Point(MinPoint.X, 214 + SubstationPoint.Y);
                }
                else if (a == 1)
                {
                    From = new Point(MaxPoint.X, 214 + SubstationPoint.Y);
                    To = new Point(180, 214 + SubstationPoint.Y);
                }
                else if (a == 2)
                {
                    From = new Point(SubstationPoint.X, 214);
                    To = new Point(SubstationPoint.X, 214 + MinPoint.Y);
                }
                else
                {
                    From = new Point(SubstationPoint.X, 214 + MaxPoint.Y);
                    To = new Point(SubstationPoint.X, 214 + 180);
                }                
                DDL.WriteAttribute("origin", From.X, From.Y);
                DDL.WriteAttribute("xlocked");
                DDL.WriteAttribute("ylocked");
                DDL.WriteAttribute("point", From.X, From.Y);
                DDL.WriteAttribute("point", To.X - From.X, To.Y - From.Y);
                DDL.WriteEndTag();            
            }

            //Now, draw our lines
            foreach (KeyValuePair<MM_Line, Point> kvp in LinePoints)
            {                

                DDL.WriteStartTag("polyline", "");
                DDL.WriteAttribute("gab \"" + kvp.Key.KVLevel.Name.Replace(' ', '_').ToUpper() + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(kvp.Key);
                DDL.WriteAttribute("origin", SubstationPoint.X, SubstationPoint.Y+214);
                DDL.WriteAttribute("xlocked");
                DDL.WriteAttribute("ylocked");
                DDL.WriteAttribute("point", SubstationPoint.X, SubstationPoint.Y+214);
                DDL.WriteAttribute("point", kvp.Value.X - SubstationPoint.X, kvp.Value.Y - SubstationPoint.Y);
                DDL.WriteEndTag();
            }

            //Now, write our buttons
            splStr = "Estimated,PRIMARY,58,Estimated (Other),PRIMARYOTHER,33,Scada,SCADA,66,Scada (Other),SCADAOTHER,41".Split(',');
            for (int a = 0; a < splStr.Length; a += 3)
            {
                DDL2.WriteStartTag("keyset","VIEW_" + splStr[a+1]);
                DDL2.WriteAttribute("key","SELECT");
                DDL2.WriteAttribute("command","SET KEY505=" + (a/3) + "; REFRESH NOW;");
                DDL2.WriteEndTag();

                DDL2.WriteStartTag("cam", "VIEW_" + splStr[a + 1]);
                DDL2.WriteAttribute("database", "NETMOM");
                DDL2.WriteAttribute("record", "ST");
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("foreground", "MediumGrey");
                DDL2.WriteAttribute("line_width", 2);
                DDL2.WriteAttribute("not fill");
                DDL2.WriteEndTag();                
                DDL2.WriteAttribute("if proxy(\"%KEY505%\") eq " + (a/3));
                DDL2.WriteStartTag("gab", "");
                DDL2.WriteAttribute("visible");
                DDL2.WriteAttribute("foreground", "MediumGrey");
                DDL2.WriteAttribute("line_width", 2);
                DDL2.WriteAttribute("fill");
                DDL2.WriteEndTag();                               
                DDL2.WriteEndTag();
                
               

                DDL.WriteStartTag("picture", "VIEW_BUTTON");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("cam \"VIEW_" + splStr[a + 1] + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("keyset \"VIEW_" + splStr[a + 1] + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", 26, 405 + (a * 14));                
                DDL.WriteAttribute("xlocked");
                DDL.WriteAttribute("ylocked");
                DDL.WriteStartTag("composite_key", "");
                DDL.WriteAttribute("record", "ST");
                DDL.WriteAttribute("record_key", SubElement.Name.ToUpper());
                DDL.WriteEndTag();
                DDL.WriteEndTag();

                DDL.WriteStartTag("text", "");
                DDL.WriteAttribute("gab \"HYPERLINK\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", float.Parse(splStr[a + 2]), 414 + (a * 14));
                DDL.WriteAttribute("xlocked");
                DDL.WriteAttribute("ylocked");
                DDL.WriteAttribute("localize \"" + splStr[a] + "\"");
                DDL.WriteEndTag();
            }

        }

        /// <summary>
        /// Determine the closest requesed color
        /// </summary>
        /// <param name="InColor"></param>
        /// <param name="FGColors"></param>
        /// <returns></returns>
        private static String ClosestColor(Color InColor, Dictionary<String, Color> FGColors)
        {
            

            float Closest = float.NaN;
            String BestColor = "";
            foreach (KeyValuePair<String, Color> kvp in FGColors)
            {
                //Find the closest hue;
                float ThisVal = (float)Math.Sqrt(Math.Pow(kvp.Value.GetHue() - InColor.GetHue(), 2) + Math.Pow(kvp.Value.GetSaturation() - InColor.GetSaturation(), 2) + Math.Pow(kvp.Value.GetBrightness() - InColor.GetBrightness(), 2));

                //float ThisVal = (float)(Math.Pow(kvp.Value.R - InColor.R,2) + Math.Pow(kvp.Value.G - InColor.G,2) + Math.Pow(kvp.Value.B - InColor.B,2));
                if (float.IsNaN(Closest) || ThisVal < Closest)                
                {
                    Closest = ThisVal;
                    BestColor = kvp.Key;
                }
            }
            return BestColor;
        }

        /// <summary>
        /// Add a SCADA telemetry point, as needed
        /// </summary>
        /// <param name="Elem"></param>
        /// <param name="Layer"></param>
        /// <param name="Substation"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Location"></param>
        /// <param name="Point">The analog's point name</param>
        private static void AddSCADAAnalog(MM_OneLine_Element Elem, String Layer, MM_Substation Substation, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, ref Point Location, string Point)
        {
            if (Layer.EndsWith("OTHER"))
                DDL.WriteStartTag("picture", "ANALOG_" + Elem.Descriptor.Orientation.ToString().Substring(0, 1));
            else
                DDL.WriteStartTag("picture", "ANALOG_" + Elem.Descriptor.InvertedOrientation.ToString().Substring(0, 1));
            DDL.WriteAttribute("set", "ERCOTONELINES");

            if (Elem is MM_OneLine_Line)
                DDL.WriteAttribute("cam", "LINE_" + Layer);
            else if (Elem is MM_OneLine_Transformer)
                DDL.WriteAttribute("cam", "SCADAMOM_TRANSFORMER_DESCRIPTOR");
            else
                DDL.WriteAttribute("cam", "SCADAMOM_" + Elem.BaseElement.ElemType.Name.ToUpper());
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("origin", Location.X, Location.Y);

            List<string> Telems = new List<string>();
            Telems.Add("Telemetry points:");
            foreach (CIM_Element InLink in MM_Database_CIM.TEIDs[Elem.BaseElement.TEID].InLinks)
                if (InLink.Type == "cim:Analog" && InLink.Parse("cim:AnalogValue") != null)
                    Telems.Add("  " + InLink.Name);
            
            DDL.WriteToolTip(Elem.BaseElement,Telems.ToArray());
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "SUBSTN");
            DDL.WriteAttribute("record_key", Substation.Name.ToUpper());
            DDL.WriteAttribute("record", "DEVTYP");
            if (Elem is MM_OneLine_Load)
                DDL.WriteAttribute("record_key", "LD");
            else if (Elem is MM_OneLine_Line)
                DDL.WriteAttribute("record_key", "LN");
            else if (Elem is MM_OneLine_Transformer)
            {
                CIM_Element XF = MM_Database_CIM.TEIDs[(Elem as MM_OneLine_Transformer).Windings[(Layer == "UP" ? 0 : 1)].BaseElement.TEID].Parse("cim:Terminal>cim:Analog>cim:AnalogValue>etx:MeasurementGroup>etx:MeasurementLocation");
                foreach (CIM_Element MeasLocation in XF.Links)
                    if (MeasLocation.Type == "etx:DeviceTypeName")
                        DDL.WriteAttribute("record_key", MeasLocation.Name);
                    
                
            }
            else if (Elem is MM_OneLine_Unit)
                DDL.WriteAttribute("record_key", "UN");

            DDL.WriteAttribute("record", "DEVICE");
            if (Elem is MM_OneLine_Transformer && Layer == "UP")
                DDL.WriteAttribute("record_key", (Elem as MM_OneLine_Transformer).Windings[0].BaseElement.Name.ToUpper());
            else if (Elem is MM_OneLine_Transformer)
                DDL.WriteAttribute("record_key", (Elem as MM_OneLine_Transformer).Windings[1].BaseElement.Name.ToUpper());
            else
                DDL.WriteAttribute("record_key", Elem.BaseElement.Name.ToUpper());
            DDL.WriteAttribute("record", "ANALOG");
            DDL.WriteAttribute("record_key", Point);
            DDL.WriteEndTag();
            DDL.WriteEndTag();
            Location.Y += 16;
        }

        /// <summary>
        /// Go through the available computed telemetry points for an item, and add it in
        /// </summary>
        /// <param name="Elem"></param>
        /// <param name="Layer"></param>
        /// <param name="Substation"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Location"></param>
        private static void AddSCADATelemetryPoints(MM_OneLine_Element Elem, String Layer, MM_Substation Substation, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Location)
        {
            List<String> TelemPoints = new List<string>(5);
            MM_Substation TargetSub = Substation;


            if (Elem is MM_OneLine_Line)
            {
                CIM_Element FoundElem = MM_Database_CIM.TEIDs[Elem.TEID];
                foreach (CIM_Element InLink in FoundElem.InLinks)
                    if (InLink.Type == "cim:Analog" && InLink.Parse("cim:AnalogValue") != null)
                    {
                        TelemPoints.Add(InLink.Name);
                        if (Layer.EndsWith("OTHER") ^ (Elem.BaseElement as MM_Line).Substation1 == Substation)
                            TargetSub = (Elem.BaseElement as MM_Line).Substation1;
                        else
                            TargetSub = (Elem.BaseElement as MM_Line).Substation2;
                    }
            }
            else if (Elem is MM_OneLine_Transformer)
            {
                CIM_Element Winding = MM_Database_CIM.TEIDs[(Elem as MM_OneLine_Transformer).Windings[(Layer == "UP" ? 0 : 1)].BaseElement.TEID];
                foreach (CIM_Element InLink in Winding.Parse("cim:Terminal").InLinks)
                    if (InLink.Type == "cim:Analog" && InLink.Parse("cim:AnalogValue") != null)
                        TelemPoints.Add(InLink.Name);
            }
            else
            {
                CIM_Element FoundElem = MM_Database_CIM.TEIDs[Elem.TEID];
                foreach (CIM_Element InLink in FoundElem.InLinks)
                    if (InLink.Type == "cim:Analog" && InLink.Parse("cim:AnalogValue") != null)
                        TelemPoints.Add(InLink.Name);
            }

            if (Layer == "UP")
            {
                int Y = Location.Y;                
                foreach (String str in "MVA,MW,MVAR,KV".Split(','))
                    if (TelemPoints.Contains(str))
                    {
                        Point NewPoint = new Point(Location.X, Y);
                        AddSCADAAnalog(Elem, Layer, TargetSub, DDL, DDL2, olView, ref NewPoint, str);
                        Y -= 16;
                    }
            }
            else
                foreach (String str in "MVA,MW,MVAR,KV".Split(','))
                    if (TelemPoints.Contains(str))
                        AddSCADAAnalog(Elem, Layer, TargetSub, DDL, DDL2, olView, ref Location, str);
        }

        /// <summary>
        /// Write out a label
        /// </summary>
        /// <param name="Elem"></param>
        /// <param name="Layer"></param>
        /// <param name="Substation"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>
        private static void WriteLabel(MM_OneLine_Element Elem, String Layer, MM_Substation Substation, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {
            if (Elem is MM_OneLine_Breaker)
            {
                DDL.WriteStartTag("text", "");
                DDL.WriteAttribute("gab \"" + ((Elem as MM_OneLine_Breaker).HasSynchroscope ? "HYPERLINK" : "TEXTCOLOR") + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(Elem.BaseElement);
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X+2, Elem.Descriptor.Top + Offset.Y);
                DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                DDL.WriteEndTag();
            }
            else if (Elem is MM_OneLine_Transformer)
            {
                //First, write out the transformer label
                DDL.WriteStartTag("text", "");
                DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(Elem.BaseElement);
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y);
                DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                DDL.WriteEndTag();

                //Write the point for the winding above
                DDL.WriteStartTag("picture", "TRANSFORMER_DESCRIPTOR_" + (Elem as MM_OneLine_Transformer).Windings[0].Orientation.ToString().Substring(0, 1));
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("cam", "NETMOM_TRANSFORMER");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y - 16 );
                DDL.WriteStartTag("composite_key", "");
                DDL.WriteAttribute("record", "ST");
                DDL.WriteAttribute("record_key", Elem.BaseElement.Substation.Name.ToUpper());
                DDL.WriteAttribute("record", "ND");
                foreach (CIM_Element Node in MM_Database_CIM.Elements[(Elem as MM_OneLine_Transformer).Windings[0].rdfID].Nodes)
                    if (Node.Type == "cim:ConnectivityNode")
                        DDL.WriteAttribute("record_key", Node.Name.ToUpper());
                DDL.WriteAttribute("record", "XF2");
                DDL.WriteAttribute("record_key", (Elem as MM_OneLine_Transformer).Windings[0].BaseElement.Name.ToUpper());
                DDL.WriteEndTag();
                DDL.WriteEndTag();

                //Write the point for the winding below
                DDL.WriteStartTag("picture", "TRANSFORMER_DESCRIPTOR_" + (Elem as MM_OneLine_Transformer).Windings[1].Orientation.ToString().Substring(0, 1));
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("cam", "NETMOM_TRANSFORMER");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y +16);
                DDL.WriteStartTag("composite_key", "");
                DDL.WriteAttribute("record", "ST");
                DDL.WriteAttribute("record_key", Elem.BaseElement.Substation.Name.ToUpper());
                DDL.WriteAttribute("record", "ND");
                foreach (CIM_Element Node in MM_Database_CIM.Elements[(Elem as MM_OneLine_Transformer).Windings[1].rdfID].Nodes)
                    if (Node.Type == "cim:ConnectivityNode")
                        DDL.WriteAttribute("record_key", Node.Name.ToUpper());
                DDL.WriteAttribute("record", "XF2");
                DDL.WriteAttribute("record_key", (Elem as MM_OneLine_Transformer).Windings[1].BaseElement.Name.ToUpper());
                DDL.WriteEndTag();
                DDL.WriteEndTag();

                //Write the winding above for SCADA
                AddSCADATelemetryPoints(Elem, "UP", Substation, DDL, DDL2, olView, new Point(Elem.Descriptor.Left + Offset.X, Offset.Y + Elem.Descriptor.Top - 16));
                AddSCADATelemetryPoints(Elem, "DOWN", Substation, DDL, DDL2, olView, new Point(Elem.Descriptor.Left + Offset.X, Offset.Y + Elem.Descriptor.Top + 15));
            }
            else if (Elem is MM_OneLine_Load)
            {
                if (Layer == "NETMOM")
                {
                    //Write out our NETMOM indicator
                    DDL.WriteStartTag("picture", "LOAD_DESCRIPTOR_" + Elem.Descriptor.Orientation.ToString().Substring(0,1) );
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("cam", "NETMOM_LOAD");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteToolTip(Elem.BaseElement);
                    DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y+16);
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "ST");
                    DDL.WriteAttribute("record_key", Elem.BaseElement.Substation.Name.ToUpper());
                    DDL.WriteAttribute("record", "LD");
                    DDL.WriteAttribute("record_key", Elem.BaseElement.Name.ToUpper());
                    DDL.WriteEndTag();
                    DDL.WriteEndTag();
                }
                else if (Layer == "SCADA")
                {
                    //Write out our SCADA layer
                    DDL.WriteStartTag("text", "");
                    DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteToolTip(Elem.BaseElement);
                    DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y);
                    DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                    DDL.WriteEndTag();

                    AddSCADATelemetryPoints(Elem, Layer, Substation, DDL, DDL2, olView, new Point(Elem.Descriptor.Left + Offset.X, Offset.Y + Elem.Descriptor.Top + 15));
                }
            }
            else if (Elem is MM_OneLine_Unit)
            {
                //First, write out the unit information
                DDL.WriteStartTag("text", "");
                DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(Elem.BaseElement);
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y);
                DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                DDL.WriteEndTag();

                //Now, if we have virtual units, let's add them in
                Point EndPos;
                using (Font MeasureFont = new Font("Arial", 12))
                using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
                {
                    EndPos = Point.Ceiling(g.MeasureString(Elem.BaseElement.Name + " ", MeasureFont).ToPointF());
                    EndPos.X += Elem.Descriptor.Left + Offset.X;
                    EndPos.Y += Elem.Descriptor.Top + Offset.Y;
                    foreach (CIM_Element OwnerShareLimit in MM_Database_CIM.TEIDs[Elem.BaseElement.TEID].InLinks)
                        if (OwnerShareLimit.Type == "etx:OwnerShareLimits")
                            foreach (CIM_Element Operatorship in OwnerShareLimit.OutLinks)
                                if (Operatorship.Type == "etx:Operatorship")
                                    foreach (CIM_Element Company in Operatorship.OutLinks)
                                        if (Company.Type == "cim:Company")
                                        {
                                            String UnitName = OwnerShareLimit.Name.Substring(OwnerShareLimit.Name.LastIndexOf('_') + 1);
                                            DDL.WriteStartTag("text", "");
                                            DDL.WriteAttribute("gab \"HYPERLINK\"");
                                            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                                            DDL.WriteAttribute("origin", EndPos.X, EndPos.Y);
                                            DDL.WriteAttribute(String.Format("tool_tip(localize \"Virtual unit {0}\r\tTEID: {1:#,##0}\r\tOwner ({2}%): {3}\rDUNS: {4}\rPhone: {5}\")", OwnerShareLimit.Name, UInt64.Parse(OwnerShareLimit.TEID), Operatorship["etx:Operatorship.operatePercent"], Company.Name, Company["etx:Company.DUNS"], Company["etx:Company.PrimaryPhone"]));
                                            DDL.WriteAttribute("localize \"" + UnitName + "\"");
                                            DDL.WriteEndTag();
                                            EndPos.X += (int)Math.Ceiling(g.MeasureString(UnitName + " ", MeasureFont).Width);
                                        }
                }

                //Now, write out our telemetry information
                if (Layer == "NETMOM")
                {
                    //Write out our NETMOM indicator
                    DDL.WriteStartTag("picture", "UNIT_DESCRIPTOR_" + Elem.Descriptor.Orientation.ToString().Substring(0,1));
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("cam", "NETMOM_UNIT");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteToolTip(Elem.BaseElement);
                    DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y + 16);
                    DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "ST");
                    DDL.WriteAttribute("record_key", Elem.BaseElement.Substation.Name.ToUpper());
                    DDL.WriteAttribute("record", "UN");
                    DDL.WriteAttribute("record_key", Elem.BaseElement.Name.ToUpper());
                    DDL.WriteEndTag();
                    DDL.WriteEndTag();
                }
                else if (Layer == "SCADA")
                {
                    //Write out our SCADA layer
                    DDL.WriteStartTag("text", "");
                    DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteToolTip(Elem.BaseElement);
                    DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y);
                    DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                    DDL.WriteEndTag();

                    AddSCADATelemetryPoints(Elem, Layer, Substation, DDL, DDL2, olView, new Point(Elem.Descriptor.Left + Offset.X, Offset.Y + Elem.Descriptor.Top + 16));
                }
            }
            else if (Elem is MM_OneLine_Line)
            {
                MM_OneLine_Line Line = Elem as MM_OneLine_Line;
                DDL.WriteStartTag("picture", "LINE_" + Substation.Name.ToUpper() + "_" + Line.BaseElement.Name.ToUpper() + "_DESCRIPTOR_" + Layer);

                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("cam \"LINE_" + Layer + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());

                DDL.WriteAttribute("origin", Line.Descriptor.Left + Offset.X + 2, Offset.Y + Line.Descriptor.Top);
                //DDL.WriteToolTip(Elem.BaseElement, OutLines.ToArray());
                DDL.WriteStartTag("composite_key", "");


                //Find the node attached to this line element
                CIM_Element LineElem = MM_Database_CIM.TEIDs[Line.BaseElement.TEID];
                foreach (CIM_Element Node in LineElem.Nodes)
                    if (Convert.ToUInt64(Node.Substation.TEID) == Substation.TEID ^ Layer.EndsWith("OTHER"))
                    {
                        if (Layer.StartsWith("SCADA"))
                        {
                            DDL.WriteAttribute("record", "SUBSTN");
                            DDL.WriteAttribute("record_key", Node.Substation.Name);
                            DDL.WriteAttribute("record", "DEVTYP");
                            DDL.WriteAttribute("record_key", "LN");
                            DDL.WriteAttribute("record", "DEVICE");
                            DDL.WriteAttribute("record_key", Line.BaseElement.Name.ToUpper());
                            DDL.WriteAttribute("record", "ANALOG");
                            DDL.WriteAttribute("record_key", "MW");

                        }
                        else
                        {
                            DDL.WriteAttribute("record", "ST");
                            DDL.WriteAttribute("record_key", Node.Substation.Name.ToUpper());
                            DDL.WriteAttribute("record", "ND");
                            DDL.WriteAttribute("record_key", Node.Name.ToUpper());
                            DDL.WriteAttribute("record", "LN2");
                            DDL.WriteAttribute("record_key", Line.BaseElement.Name.ToUpper());
                        }
                    }

                DDL.WriteEndTag();
                DDL.WriteEndTag();

                //Now, if we have a SCADA layer, add in the extra points
                if (Layer.StartsWith("SCADA"))
                    AddSCADATelemetryPoints(Elem, Layer, Substation, DDL, DDL2, olView, new Point(Elem.Descriptor.Left + Offset.X, Offset.Y + Elem.Descriptor.Top + 16));

            }
            else
            {
                DDL.WriteStartTag("text", "");
                DDL.WriteAttribute("gab \"TEXTCOLOR\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(Elem.BaseElement);
                DDL.WriteAttribute("origin", Elem.Descriptor.Left + Offset.X + 2, Elem.Descriptor.Top + Offset.Y);
                DDL.WriteAttribute("localize \"" + Elem.BaseElement.Name + "\"");
                DDL.WriteEndTag();
            }
        }

        /// <summary>
        /// Write the information out on a breaker
        /// </summary>
        /// <param name="Breaker"></param>
        /// <param name="SubElement"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="Offset"></param>
        private static void WriteBreaker(MM_OneLine_Breaker Breaker, MM_Element SubElement, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, Point Offset)
        {
            DDL.WriteStartTag("picture", "BREAKER_" + Breaker.KVLevel.Name.Replace(' ', '_').ToUpper() + "_NET");                
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "NETMOM_BREAKER");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());            
            DDL.WriteAttribute("origin", Offset.X + Breaker.Left + 1, Offset.Y + Breaker.Top - 1);
            DDL.WriteToolTip(Breaker.BaseElement,"NETMOM State: %%OPEN_CB%%");
            DDL.WriteStartTag("composite_key", "");
            DDL.WriteAttribute("record", "ST");
            DDL.WriteAttribute("record_key", SubElement.Name.ToUpper());
            DDL.WriteAttribute("record", "CBTYP");
            DDL.WriteAttribute("record_key", "CB");
            DDL.WriteAttribute("record", "CB");
            DDL.WriteAttribute("record_key", Breaker.BaseElement.Name.ToUpper());
            DDL.WriteEndTag();
            DDL.WriteEndTag();

            DDL.WriteStartTag("picture", "BREAKER_" + Breaker.KVLevel.Name.Replace(' ', '_').ToUpper() + "_SCADA");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());
            DDL.WriteAttribute("cam", "SCADAMOM_BREAKER");
            DDL.WriteAttribute("set", DDL2.Name.ToUpper());  
            DDL.WriteAttribute("origin", Offset.X + Breaker.Left + 1, Offset.Y + Breaker.Top - 1);
            DDL.WriteToolTip(Breaker.BaseElement, "SCADA state: %%SDIS_POINT%%","SCADA unack: %%UNACK_POINT%%");
            DDL.WriteStartTag("composite_key", "");                        
            DDL.WriteAttribute("record", "SUBSTN");
            DDL.WriteAttribute("record_key", SubElement.Name.ToUpper());
            DDL.WriteAttribute("record", "DEVTYP");
            DDL.WriteAttribute("record_key", "CB");
            DDL.WriteAttribute("record", "DEVICE");
            DDL.WriteAttribute("record_key", Breaker.BaseElement.Name.ToUpper());
            DDL.WriteAttribute("record", "POINT");
            DDL.WriteAttribute("record_key", "ST");
            DDL.WriteEndTag();
            DDL.WriteEndTag();
        }

        /// <summary>
        /// Write out a line's information
        /// </summary>
        /// <param name="Line"></param>
        /// <param name="SubElement"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="olView"></param>
        /// <param name="Offset"></param>
        private static void WriteLine(MM_OneLine_Line Line, MM_Substation SubElement, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, MM_OneLine_Viewer olView, Point Offset)
        {
            //Add in our Keyset for this substation            
            MM_Line BaseElement = Line.BaseElement as MM_Line;

           
                DDL.WriteStartTag("picture","LINE_NET_" + Line.KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + Line.Orientation.ToString().Substring(0, 1));
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteAttribute("origin", Line.Left + 1 + Offset.X, Offset.Y + Line.Top + 1);

                List<String> OutLines = new List<string>();


                if (BaseElement.ConnectedStations[0].County == BaseElement.ConnectedStations[1].County)
                {
                    if (BaseElement.ConnectedStations[0].County != null)
                        OutLines.Add("  County: " + BaseElement.ConnectedStations[0].County.Name);
                    if (BaseElement.ConnectedStations[0] == SubElement)
                        OutLines.Add("  To " + BaseElement.ConnectedStations[1].DisplayName);
                    else if (BaseElement.ConnectedStations[1] == SubElement)
                        OutLines.Add("  To " + BaseElement.ConnectedStations[0].DisplayName);
                    else
                    {
                        OutLines.Add("  Between " + BaseElement.ConnectedStations[0].DisplayName);
                        OutLines.Add("  And " + BaseElement.ConnectedStations[1].DisplayName);
                    }
                }
                else
                {
                    if (BaseElement.ConnectedStations[0].County != null)
                        OutLines.Add("  Between " + BaseElement.ConnectedStations[0].DisplayName + " (" + BaseElement.ConnectedStations[0].County.Name + " county)");
                    else
                        OutLines.Add("  Between " + BaseElement.ConnectedStations[0].DisplayName);
                    if (BaseElement.ConnectedStations[1].County != null)
                        OutLines.Add("  And     " + BaseElement.ConnectedStations[1].DisplayName + " (" + BaseElement.ConnectedStations[1].County.Name + " county)");
                    else
                        OutLines.Add("  And     " + BaseElement.ConnectedStations[1].DisplayName);
                }
                OutLines.Add("  Est. Distance: " + BaseElement.Length.ToString("#,##0") + " miles");
                           

                
                    OutLines.Add("------");
                    OutLines.Add("       %%P__LN_LNLIM I__LN2_LN P__ND_LN2 P__KV_ND P__ST_KV ID_ST%%           %%P__LN_LNLIM Z__LN2_LN P__ND_LN2 P__KV_ND P__ST_KV ID_ST%%");
                    OutLines.Add("                           Estimated   ");
                    OutLines.Add("MVA:    %%P__LN_LNLIM I__LN2_LN MVA_LN2%%       %%P__LN_LNLIM Z__LN2_LN MVA_LN2%%");
                    OutLines.Add("MW:     %%P__LN_LNLIM I__LN2_LN W_LN2%%       %%P__LN_LNLIM Z__LN2_LN W_LN2%%");
                    OutLines.Add("MVAR:   %%P__LN_LNLIM I__LN2_LN R_LN2%%       %%P__LN_LNLIM Z__LN2_LN R_LN2%%");
                    OutLines.Add("");
                    OutLines.Add("Limits:  %%LIMIT1_LNLIM%%  %%LIMIT2_LNLIM%%  %%LIMIT3_LNLIM%%");
                    OutLines.Add("");
                    OutLines.Add("                      Telemetered (Last SE)");
                    OutLines.Add("MW:     %%P__LN_LNLIM I__LN2_LN WMEAS_LN2%%       %%P__LN_LNLIM Z__LN2_LN WMEAS_LN2%%");
                    OutLines.Add("MVAR:   %%P__LN_LNLIM I__LN2_LN RMEAS_LN2%%       %%P__LN_LNLIM Z__LN2_LN RMEAS_LN2%%");                    
                

                DDL.WriteToolTip(BaseElement, OutLines.ToArray());
                DDL.WriteStartTag("composite_key", "");
                    DDL.WriteAttribute("record", "LINE");
                    DDL.WriteAttribute("record_key", Line.BaseElement.Name.ToUpper());
                    DDL.WriteAttribute("record", "LN");
                    DDL.WriteAttribute("record_key", "1");
                    DDL.WriteAttribute("record", "LNLIM");
                    DDL.WriteAttribute("record_key", "1");                
                DDL.WriteEndTag();
                DDL.WriteEndTag();
        

            if (Line.Descriptor != null)
            {
                //Write our descriptors
                foreach (String Layer in "PRIMARY,OTHER,SCADA,SCADAOTHER".Split(','))
                {

                    DDL2.WriteStartTag("picture", "LINE_" + SubElement.Name.ToUpper() + "_" +  Line.BaseElement.Name.ToUpper() + "_DESCRIPTOR_" + Layer);
                    if (Layer.StartsWith("SCADA")) 
                    {
                        DDL2.WriteAttribute("application", "SCADA");
                        DDL2.WriteAttribute("database", "SCADAMOM");
                        DDL2.WriteAttribute("record", "ANALOG");
                    }
                    else
                    {
                        DDL2.WriteAttribute("database", "NETMOM");
                        DDL2.WriteAttribute("record", "LN2");
                    }
                    DDL2.WriteStartTag("text", "");
                    DDL2.WriteAttribute("gab \"HYPERLINK\"");
                    DDL2.WriteAttribute("origin", 0, 0);
                    String StartText;
                    if (Layer == "PRIMARY")
                        StartText = "";
                    else if (Layer == "OTHER")
                        StartText = "(from) ";
                    else if (Layer == "SCADA")
                        StartText = "(scada) ";
                    else
                        StartText = "(scada from) ";


                    //Write our text and hyperlink
                    if (BaseElement.ConnectedStations[0] == SubElement)
                    {
                        DDL2.WriteAttribute("keyset \"" + BaseElement.ConnectedStations[1].Name.ToUpper() + "_CALLUP\"");
                        if (String.IsNullOrEmpty(BaseElement.ConnectedStations[1].LongName) || BaseElement.ConnectedStations[1].LongName == BaseElement.ConnectedStations[1].Name)
                            DDL2.WriteAttribute("tool_tip(localize \"Navigate to " + BaseElement.ConnectedStations[1].Name + "\" )");
                        else
                            DDL2.WriteAttribute("tool_tip(localize \"Navigate to " + BaseElement.ConnectedStations[1].LongName + " (" + BaseElement.ConnectedStations[1].Name + ")\" )");                                                
                        DDL2.WriteAttribute("localize \"" + StartText + BaseElement.ConnectedStations[1].LongName + "\"");

                    }
                    else
                    {
                        DDL2.WriteAttribute("keyset \"" + BaseElement.ConnectedStations[0].Name.ToUpper() + "_CALLUP\"");
                        if (String.IsNullOrEmpty(BaseElement.ConnectedStations[0].LongName) || BaseElement.ConnectedStations[0].LongName == BaseElement.ConnectedStations[0].Name)
                            DDL2.WriteAttribute("tool_tip(localize \"Navigate to " + BaseElement.ConnectedStations[0].Name + "\" )");
                        else
                            DDL2.WriteAttribute("tool_tip(localize \"Navigate to " + BaseElement.ConnectedStations[0].LongName + " (" + BaseElement.ConnectedStations[0].Name + ")\" )");                
                        DDL2.WriteAttribute("localize \"" + StartText + BaseElement.ConnectedStations[0].LongName + "\"");
                    }
                    DDL2.WriteEndTag();

                    if (!Layer.StartsWith("SCADA"))
                    {
                        //Write out our label
                        String[] Title = "MVA,MW,MVAR".Split(',');
                        String[] Keys = "MVA,W,R".Split(',');
                        for (int a = 0; a < 3; a++)
                        {
                            DDL2.WriteStartTag("formatted_field", "");
                            DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                            DDL2.WriteAttribute("origin", 0, 16 + (a * 16));
                            DDL2.WriteAttribute("show_char", a.ToString());
                            DDL2.WriteAttribute("size", 5);
                            DDL2.WriteAttribute("position", 1);
                            DDL2.WriteAttribute("format(int)");
                            DDL2.WriteAttribute("factor(1.0000000)");
                            DDL2.WriteAttribute("justification(right) sign_textpair");

                            if (Layer == "PRIMARY")
                            {
                                DDL2.WriteAttribute("plus_textpair(bitmap(\"" + Line.Descriptor.Orientation.ToString().ToLower() + "_arrow\"))");
                                DDL2.WriteAttribute("minus_textpair(bitmap(\"" + Line.Descriptor.InvertedOrientation.ToString().ToLower() + "_arrow\"))");                                                             
                            }
                            else
                            {
                                DDL2.WriteAttribute("plus_textpair(bitmap(\"" + Line.Descriptor.InvertedOrientation.ToString().ToLower() + "_arrow\"))");
                                DDL2.WriteAttribute("minus_textpair(bitmap(\"" + Line.Descriptor.Orientation.ToString().ToLower() + "_arrow\"))");                                
                            }

                            DDL2.WriteAttribute("refresh_field");
                            DDL2.WriteAttribute("not refresh_indirect");
                            DDL2.WriteAttribute("not enterable");
                            DDL2.WriteAttribute("show");
                            DDL2.WriteAttribute("field", Keys[a] + "_LN2");
                            DDL2.WriteEndTag();

                            DDL2.WriteStartTag("text", "");
                            DDL2.WriteAttribute("gab \"TEXTCOLOR\"");
                            DDL2.WriteAttribute("origin", 51, 16 + (a * 16));
                            DDL2.WriteAttribute("localize \"" + Title[a] + "\"");
                            DDL2.WriteEndTag();
                        }
                    }
                    DDL2.WriteEndTag();
                }
            }
        }
        

        /// <summary>
        /// Write out a node's information
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="SubElement"></param>
        /// <param name="DDL"></param>
        /// <param name="DDL2"></param>
        /// <param name="Offset"></param>
        private static void WriteNode(MM_OneLine_Node Node, MM_Element SubElement, MM_DDL_Exporter_Stream DDL, MM_DDL_Exporter_Stream DDL2, Point Offset)
        {
            
            //Draw our node lines
            foreach (KeyValuePair<MM_OneLine_Element, GraphicsPath> kvp in Node.GraphicsPaths)
            {
                DDL.WriteStartTag("polyline", "");
                DDL.WriteAttribute("gab \"" + Node.BaseElement.KVLevel.Name.Replace(' ','_').ToUpper() + "\"");
                DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                DDL.WriteToolTip(Node.BaseElement, "Path to " + kvp.Key.BaseElement.ElemType.Name + " " + kvp.Key.BaseElement.Name);
                PointF pt = kvp.Value.PathData.Points[0];
                DDL.WriteAttribute("origin", pt.X + Offset.X, Offset.Y+ pt.Y);
                pt = new Point(-Offset.X, -Offset.Y);
                List<PointF> Points = new List<PointF>(kvp.Value.PathPoints);
               
               /* if (Node.Size != new Size(7, 7) && Node.Size != new Size(8, 8))
                    for (int a = 0; a < 2; a++)
                        Points.RemoveAt(0);*/
                foreach (PointF pt2 in Points)                
                {
                    DDL.WriteAttribute("point", pt2.X - pt.X, pt2.Y - pt.Y);
                    pt = pt2;
                }
                DDL.WriteEndTag();
            }

            if (Node.Size == new Size(8,8) || Node.Size == new Size(7,7))
            {
                foreach (String str in "NET,SCADA".Split(','))
                {
                    DDL.WriteStartTag("picture", "NODE_" + Node.KVLevel.Name.Replace(' ', '_').ToUpper() + "_" + str);
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("cam \"" + str + "MOM_NODE\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("origin", Offset.X + Node.Left - 1, Offset.Y + Node.Top - 1);
                    if (str == "NET")
                    {
                        DDL.WriteToolTip(Node.BaseElement, "Voltage: %%I$BS_ND KV_BS%% (%%I$BS_ND V_BS%% pU)", "Angle: %%I$BS_ND ADEG_BS%%");
                        DDL.WriteStartTag("composite_key", "");
                        DDL.WriteAttribute("record", "ST");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Substation.Name.ToUpper());
                        DDL.WriteAttribute("record", "ND");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Name.ToUpper());
                        DDL.WriteEndTag();
                    }
                    else
                    {
                        DDL.WriteToolTip(Node.BaseElement, "Voltage: %%DIS_ANALOG%%");
                        DDL.WriteStartTag("composite_key", "");
                        DDL.WriteAttribute("record", "SUBSTN");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Substation.Name.ToUpper());
                        DDL.WriteAttribute("record", "DEVTYP");
                        DDL.WriteAttribute("record_key", "BS");
                        DDL.WriteAttribute("record", "DEVICE");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Name.ToUpper());
                        DDL.WriteAttribute("record", "ANALOG");
                        DDL.WriteAttribute("record_key", "KV");
                        DDL.WriteEndTag();
                    }
                    DDL.WriteEndTag();
                }
            }
            else
                foreach (String str in "NET,SCADA".Split(','))
                {
                    //We have a rectangular node, so we have to set up things to work properly.
                    DDL2.WriteStartTag("picture", "NODE_" + Node.BaseElement.Substation.Name.ToUpper() + "_" + Node.BaseElement.Name.ToUpper() + "_" + str);
                    if (str == "SCADA")
                        DDL2.WriteAttribute("application", str);
                    DDL2.WriteAttribute("database", str + "MOM");
                    DDL2.WriteAttribute("record", str == "NET" ? "ND" : "ANALOG");
                    DDL2.WriteStartTag("rectangle", "");
                    DDL2.WriteAttribute("gab \"" + Node.BaseElement.KVLevel.Name.Replace(' ', '_') + "\"");
                    DDL2.WriteAttribute("origin", 0, 0);
                    DDL2.WriteAttribute("width", Node.Width);
                    DDL2.WriteAttribute("height", Node.Height);
                    DDL2.WriteEndTag();
                    DDL2.WriteEndTag();

                    DDL.WriteStartTag("picture", "NODE_" + Node.BaseElement.Substation.Name.ToUpper() + "_" +  Node.BaseElement.Name.ToUpper() + "_" + str);
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("cam \"" + str + "MOM_NODE\"");
                    DDL.WriteAttribute("set", DDL2.Name.ToUpper());
                    DDL.WriteAttribute("origin", Node.Left + Offset.X, Offset.Y + Node.Top);
                    if (str == "NET")
                    {
                        DDL.WriteToolTip(Node.BaseElement, "Voltage: %%I$BS_ND KV_BS%% (%%I$BS_ND V_BS%% pU)", "Angle: %%I$BS_ND ADEG_BS%%");
                        DDL.WriteStartTag("composite_key", "");
                        DDL.WriteAttribute("record", "ST");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Substation.Name.ToUpper());
                        DDL.WriteAttribute("record", "ND");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Name.ToUpper());
                        DDL.WriteEndTag();
                    }
                    else
                    {
                        DDL.WriteToolTip(Node.BaseElement, "Voltage: %%DIS_ANALOG%%");
                        DDL.WriteStartTag("composite_key", "");
                        DDL.WriteAttribute("record", "SUBSTN");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Substation.Name.ToUpper());
                        DDL.WriteAttribute("record", "DEVTYP");
                        DDL.WriteAttribute("record_key", "BS");
                        DDL.WriteAttribute("record", "DEVICE");
                        DDL.WriteAttribute("record_key", Node.BaseElement.Name.ToUpper());
                        DDL.WriteAttribute("record", "ANALOG");
                        DDL.WriteAttribute("record_key", "KV");
                        DDL.WriteEndTag();
                    }
                    DDL.WriteEndTag();
                }
        }



        /// <summary>
        /// This class holds a DDL exporter
        /// </summary>
        class MM_DDL_Exporter_Stream
        {
            #region Variable Declarations
            /// <summary>The streamwriter associated with the DDL exporting</summary>
            public StreamWriter sW;

            /// <summary>The current indentation</summary>
            public int Indentation = 0;

            public string Name;
            #endregion

            #region Initialziation
            /// <summary>
            /// Initialize a new DDL exporter
            /// </summary>
            /// <param name="FileName"></param>
            public MM_DDL_Exporter_Stream(String FileName)
            {
                sW = new StreamWriter(FileName, false, Encoding.ASCII);
                this.Name = Path.GetFileNameWithoutExtension(FileName.Substring(0, FileName.LastIndexOf('_')));
            }
            #endregion

            #region Routines
            /// <summary>
            /// Write a blank line
            /// </summary>
            public void WriteLine()
            {
                sW.WriteLine(new String('\t', Indentation));
            }

            /// <summary>
            /// Write an attribute out to the DDL export
            /// </summary>
            /// <param name="Name">The name of the attribute</param>
            /// <param name="Value">The value of the attribute</param>
            public void WriteAttribute(String Name, String Value)
            {
                if (Name == "Value")
                {
                    sW.WriteLine(new String('\t', Indentation) + "localize \"" + Value + "\"");
                    return;
                }
                if (Value == "false")
                    sW.Write(new String('\t', Indentation) + "not " + Name);
                else
                    sW.Write(new String('\t', Indentation) + Name);
                
                if (String.IsNullOrEmpty(Value))
                    sW.Write(" ");                    
                else if (Name == "cam")
                    sW.Write(" \"" + Value + "\" ");
                else if (Name == "size" || Name == "position" || Name == "factor" || Name == "lo_declutter" || Name == "hi_declutter" || Name=="format" || Name == "width" || Name == "height" || Name == "justification")
                    sW.Write("(" + Value + ")");
                else if (Value == "left arrow" || Value == "up arrow" || Value == "right arrow" || Value == "down arrow")
                    sW.Write("(bitmap(\"" + Value + "\"))");
                else if (Name == "origin")
                    sW.Write("(" + Value.Replace(',',' ') + ")");
                else if (Name == "point")
                {
                    string[] splStr = Value.Split(',');
                    sW.WriteLine("(" + splStr[0] + " " + splStr[1] + ")");
                    for (int a = 2; a < splStr.Length; a += 2)
                        WriteAttribute(Name, float.Parse(splStr[a]), float.Parse(splStr[a + 1]));
                }
                else if (Value != "true" && Value != "false")
                    sW.Write("(\"" + Value + "\") ");
                if (Indentation == 0)
                    sW.WriteLine(";");
                else
                    sW.WriteLine();
            }

            /// <summary>
            /// Write an attribute out to the DDL export
            /// </summary>
            /// <param name="Name">The name of the attribute</param>        
            public void WriteAttribute(String Name)
            {
                sW.Write(new String('\t', Indentation) + Name + " ");
                if (Indentation == 0)
                    sW.WriteLine(";");
                else
                    sW.WriteLine();
            }

            /// <summary>
            /// Write an attribute out to the DDL export
            /// </summary>
            /// <param name="Name">The name of the attribute</param>
            /// <param name="Value">The value of the attribute</param>
            public void WriteAttribute(String Name, float Value)
            {
                sW.Write(new String('\t', Indentation) + Name + "(" + Value + ") ");
                if (Indentation == 0)
                    sW.WriteLine(";");
                else
                    sW.WriteLine();
            }

            /// <summary>
            /// Write an attribute out to the DDL export
            /// </summary>
            /// <param name="Name">The name of the attribute</param>
            /// <param name="Value1">The value of the attribute</param>
            /// <param name="Value2">The second value of the attribute</param>
            public void WriteAttribute(String Name, float Value1, float Value2)
            {               
                sW.Write(new String('\t', Indentation) + Name + "(" + Value1 + " " + Value2 + ") ");
                if (Indentation == 0)
                    sW.WriteLine(";");
                else
                    sW.WriteLine();
            }

            /// <summary>
            /// Write an attribute out to the DDL export
            /// </summary>
            /// <param name="Name1">The name of the attribute</param>
            /// <param name="Name2">The second name of the attribute</param>
            /// <param name="Value">The value of the attribute</param>
            public void WriteAttribute(String Name1, String Name2, String Value)
            {
                sW.WriteLine(new String('\t', Indentation) + Name1 + "(" + Name2 + " \"" + Value + "\")");
            }
            #endregion


            /// <summary>
            /// Write the starting tag of component
            /// </summary>
            /// <param name="Name"></param>
            /// <param name="Value"></param>
            public void WriteStartTag(string Name, string Value)
            {
                if (String.IsNullOrEmpty(Value))
                    sW.WriteLine("{0}{1} ", new String('\t', Indentation), Name);
                else
                    sW.WriteLine("{0}{1} \"{2}\"", new String('\t', Indentation), Name, Value);
                sW.WriteLine(new String('\t', Indentation) + "(");
                Indentation++;
            }

            /// <summary>
            /// Write the end of a tag
            /// </summary>
            public void WriteEndTag()
            {
                Indentation--;
                if (Indentation == 1)
                    sW.WriteLine(new String('\t', Indentation) + ");");
                else
                    sW.WriteLine(new String('\t', Indentation) + ")");

            }

            /// <summary>
            /// Close and dispose of the stream writer
            /// </summary>
            public void Close()
            {
                while (Indentation > 1)
                    WriteEndTag();
                sW.Close();
                sW.Dispose();
                sW = null;
            }

            /// <summary>
            /// Write out tool tip text for the documnet
            /// </summary>
            /// <param name="BaseElement"></param>
            /// <param name="Lines"></param>
            public void WriteToolTip(MM_Element BaseElement, params string[] Lines)
            {
                sW.Write(new String('\t', Indentation) + "tool_tip(localize \"" + BaseElement.ElemType.Name + " " + BaseElement.Name + "\n");
                sW.Write("  TEID: " + BaseElement.TEID.ToString("#,##0") + "\n");

                CIM_Element MatchingCIM;
                if (MM_Database_CIM.TEIDs.TryGetValue(BaseElement.TEID, out MatchingCIM) && MatchingCIM.VoltageLevel != null)
                    sW.Write("  Voltage: " + MatchingCIM.VoltageLevel.Name + "\n");

                if (Lines.Length > 0)
                    sW.Write("-------\n");
                foreach (string Line in Lines)
                    sW.Write(Line + "\n");
                sW.Write("-------\n");
                if (BaseElement.Owner == null && BaseElement.Operator == null)
                    sW.WriteLine("No ownership or operatorship information available for {0} {1}\")", BaseElement.ElemType.Name, BaseElement.Name);
                else if (BaseElement.Owner == BaseElement.Operator)
                {
                    sW.Write("Owner/Operator: " + BaseElement.Owner.Name + "\n");
                    sW.Write("DUNS: " + BaseElement.Owner.DUNS + "\n");
                    sW.WriteLine("Phone: " + BaseElement.Owner.PrimaryPhone + "\")");
                }
                else
                {
                    sW.Write("Owner: " + BaseElement.Owner.Name + "\n");
                    sW.Write("DUNS: " + BaseElement.Owner.DUNS + "\n");
                    sW.Write("Phone: " + BaseElement.Owner.PrimaryPhone + "\n");
                    sW.Write("-------\n");
                    sW.Write("Operator: " + BaseElement.Operator.Name + "\n");
                    sW.Write("DUNS: " + BaseElement.Operator.DUNS + "\n");
                    sW.WriteLine("Phone: " + BaseElement.Operator.PrimaryPhone + "\")");
                }
            }

            /// <summary>
            /// Write a rotated attribute
            /// </summary>
            /// <param name="Name"></param>
            /// <param name="X"></param>
            /// <param name="Y"></param>
            /// <param name="Height"></param>
            /// <param name="Width"></param>
            /// <param name="Angle"></param>
            public void WriteRotatedAttribute(string Name, int X, int Y, int Width, int Height, int Angle)
            {
                if (Angle == 0)
                    WriteAttribute(Name, X, Y);
                else if (Angle == 90)
                    WriteAttribute(Name, Height - Y, Width - X);
                else if (Angle == 180)
                    WriteAttribute(Name, Width - X, Height - Y);
                else if (Angle == 270)
                    WriteAttribute(Name, Y, X);
              
            }
        }
    }
}